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:40:35 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:40:35 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:40:35 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:40:35 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:40:35 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:40:35 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:40:35 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:40:35 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/SyncFailedException.java Thu Oct 03 15:40:35 2013 +0200
9.3 @@ -0,0 +1,48 @@
9.4 +/*
9.5 + * Copyright (c) 1996, 2008, 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 + * Signals that a sync operation has failed.
9.33 + *
9.34 + * @author Ken Arnold
9.35 + * @see java.io.FileDescriptor#sync
9.36 + * @see java.io.IOException
9.37 + * @since JDK1.1
9.38 + */
9.39 +public class SyncFailedException extends IOException {
9.40 + private static final long serialVersionUID = -2353342684412443330L;
9.41 +
9.42 + /**
9.43 + * Constructs an SyncFailedException with a detail message.
9.44 + * A detail message is a String that describes this particular exception.
9.45 + *
9.46 + * @param desc a String describing the exception.
9.47 + */
9.48 + public SyncFailedException(String desc) {
9.49 + super(desc);
9.50 + }
9.51 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/Charset.java Thu Oct 03 15:40:35 2013 +0200
10.3 @@ -0,0 +1,923 @@
10.4 +/*
10.5 + * Copyright (c) 2000, 2010, 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.nio.charset;
10.30 +
10.31 +import java.nio.ByteBuffer;
10.32 +import java.nio.CharBuffer;
10.33 +import java.nio.charset.spi.CharsetProvider;
10.34 +import java.security.AccessController;
10.35 +import java.security.AccessControlException;
10.36 +import java.security.PrivilegedAction;
10.37 +import java.util.Collections;
10.38 +import java.util.HashSet;
10.39 +import java.util.Iterator;
10.40 +import java.util.Locale;
10.41 +import java.util.Map;
10.42 +import java.util.NoSuchElementException;
10.43 +import java.util.Set;
10.44 +import java.util.ServiceLoader;
10.45 +import java.util.ServiceConfigurationError;
10.46 +import java.util.SortedMap;
10.47 +import java.util.TreeMap;
10.48 +import sun.misc.ASCIICaseInsensitiveComparator;
10.49 +import sun.nio.cs.StandardCharsets;
10.50 +import sun.nio.cs.ThreadLocalCoders;
10.51 +import sun.security.action.GetPropertyAction;
10.52 +
10.53 +
10.54 +/**
10.55 + * A named mapping between sequences of sixteen-bit Unicode <a
10.56 + * href="../../lang/Character.html#unicode">code units</a> and sequences of
10.57 + * bytes. This class defines methods for creating decoders and encoders and
10.58 + * for retrieving the various names associated with a charset. Instances of
10.59 + * this class are immutable.
10.60 + *
10.61 + * <p> This class also defines static methods for testing whether a particular
10.62 + * charset is supported, for locating charset instances by name, and for
10.63 + * constructing a map that contains every charset for which support is
10.64 + * available in the current Java virtual machine. Support for new charsets can
10.65 + * be added via the service-provider interface defined in the {@link
10.66 + * java.nio.charset.spi.CharsetProvider} class.
10.67 + *
10.68 + * <p> All of the methods defined in this class are safe for use by multiple
10.69 + * concurrent threads.
10.70 + *
10.71 + *
10.72 + * <a name="names"><a name="charenc">
10.73 + * <h4>Charset names</h4>
10.74 + *
10.75 + * <p> Charsets are named by strings composed of the following characters:
10.76 + *
10.77 + * <ul>
10.78 + *
10.79 + * <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
10.80 + * (<tt>'\u0041'</tt> through <tt>'\u005a'</tt>),
10.81 + *
10.82 + * <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
10.83 + * (<tt>'\u0061'</tt> through <tt>'\u007a'</tt>),
10.84 + *
10.85 + * <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
10.86 + * (<tt>'\u0030'</tt> through <tt>'\u0039'</tt>),
10.87 + *
10.88 + * <li> The dash character <tt>'-'</tt>
10.89 + * (<tt>'\u002d'</tt>, <small>HYPHEN-MINUS</small>),
10.90 + *
10.91 + * <li> The plus character <tt>'+'</tt>
10.92 + * (<tt>'\u002b'</tt>, <small>PLUS SIGN</small>),
10.93 + *
10.94 + * <li> The period character <tt>'.'</tt>
10.95 + * (<tt>'\u002e'</tt>, <small>FULL STOP</small>),
10.96 + *
10.97 + * <li> The colon character <tt>':'</tt>
10.98 + * (<tt>'\u003a'</tt>, <small>COLON</small>), and
10.99 + *
10.100 + * <li> The underscore character <tt>'_'</tt>
10.101 + * (<tt>'\u005f'</tt>, <small>LOW LINE</small>).
10.102 + *
10.103 + * </ul>
10.104 + *
10.105 + * A charset name must begin with either a letter or a digit. The empty string
10.106 + * is not a legal charset name. Charset names are not case-sensitive; that is,
10.107 + * case is always ignored when comparing charset names. Charset names
10.108 + * generally follow the conventions documented in <a
10.109 + * href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC 2278: IANA Charset
10.110 + * Registration Procedures</i></a>.
10.111 + *
10.112 + * <p> Every charset has a <i>canonical name</i> and may also have one or more
10.113 + * <i>aliases</i>. The canonical name is returned by the {@link #name() name} method
10.114 + * of this class. Canonical names are, by convention, usually in upper case.
10.115 + * The aliases of a charset are returned by the {@link #aliases() aliases}
10.116 + * method.
10.117 + *
10.118 + * <a name="hn">
10.119 + *
10.120 + * <p> Some charsets have an <i>historical name</i> that is defined for
10.121 + * compatibility with previous versions of the Java platform. A charset's
10.122 + * historical name is either its canonical name or one of its aliases. The
10.123 + * historical name is returned by the <tt>getEncoding()</tt> methods of the
10.124 + * {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link
10.125 + * java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes.
10.126 + *
10.127 + * <a name="iana">
10.128 + *
10.129 + * <p> If a charset listed in the <a
10.130 + * href="http://www.iana.org/assignments/character-sets"><i>IANA Charset
10.131 + * Registry</i></a> is supported by an implementation of the Java platform then
10.132 + * its canonical name must be the name listed in the registry. Many charsets
10.133 + * are given more than one name in the registry, in which case the registry
10.134 + * identifies one of the names as <i>MIME-preferred</i>. If a charset has more
10.135 + * than one registry name then its canonical name must be the MIME-preferred
10.136 + * name and the other names in the registry must be valid aliases. If a
10.137 + * supported charset is not listed in the IANA registry then its canonical name
10.138 + * must begin with one of the strings <tt>"X-"</tt> or <tt>"x-"</tt>.
10.139 + *
10.140 + * <p> The IANA charset registry does change over time, and so the canonical
10.141 + * name and the aliases of a particular charset may also change over time. To
10.142 + * ensure compatibility it is recommended that no alias ever be removed from a
10.143 + * charset, and that if the canonical name of a charset is changed then its
10.144 + * previous canonical name be made into an alias.
10.145 + *
10.146 + *
10.147 + * <h4>Standard charsets</h4>
10.148 + *
10.149 + * <a name="standard">
10.150 + *
10.151 + * <p> Every implementation of the Java platform is required to support the
10.152 + * following standard charsets. Consult the release documentation for your
10.153 + * implementation to see if any other charsets are supported. The behavior
10.154 + * of such optional charsets may differ between implementations.
10.155 + *
10.156 + * <blockquote><table width="80%" summary="Description of standard charsets">
10.157 + * <tr><th><p align="left">Charset</p></th><th><p align="left">Description</p></th></tr>
10.158 + * <tr><td valign=top><tt>US-ASCII</tt></td>
10.159 + * <td>Seven-bit ASCII, a.k.a. <tt>ISO646-US</tt>,
10.160 + * a.k.a. the Basic Latin block of the Unicode character set</td></tr>
10.161 + * <tr><td valign=top><tt>ISO-8859-1 </tt></td>
10.162 + * <td>ISO Latin Alphabet No. 1, a.k.a. <tt>ISO-LATIN-1</tt></td></tr>
10.163 + * <tr><td valign=top><tt>UTF-8</tt></td>
10.164 + * <td>Eight-bit UCS Transformation Format</td></tr>
10.165 + * <tr><td valign=top><tt>UTF-16BE</tt></td>
10.166 + * <td>Sixteen-bit UCS Transformation Format,
10.167 + * big-endian byte order</td></tr>
10.168 + * <tr><td valign=top><tt>UTF-16LE</tt></td>
10.169 + * <td>Sixteen-bit UCS Transformation Format,
10.170 + * little-endian byte order</td></tr>
10.171 + * <tr><td valign=top><tt>UTF-16</tt></td>
10.172 + * <td>Sixteen-bit UCS Transformation Format,
10.173 + * byte order identified by an optional byte-order mark</td></tr>
10.174 + * </table></blockquote>
10.175 + *
10.176 + * <p> The <tt>UTF-8</tt> charset is specified by <a
10.177 + * href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC 2279</i></a>; the
10.178 + * transformation format upon which it is based is specified in
10.179 + * Amendment 2 of ISO 10646-1 and is also described in the <a
10.180 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
10.181 + * Standard</i></a>.
10.182 + *
10.183 + * <p> The <tt>UTF-16</tt> charsets are specified by <a
10.184 + * href="http://www.ietf.org/rfc/rfc2781.txt"><i>RFC 2781</i></a>; the
10.185 + * transformation formats upon which they are based are specified in
10.186 + * Amendment 1 of ISO 10646-1 and are also described in the <a
10.187 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
10.188 + * Standard</i></a>.
10.189 + *
10.190 + * <p> The <tt>UTF-16</tt> charsets use sixteen-bit quantities and are
10.191 + * therefore sensitive to byte order. In these encodings the byte order of a
10.192 + * stream may be indicated by an initial <i>byte-order mark</i> represented by
10.193 + * the Unicode character <tt>'\uFEFF'</tt>. Byte-order marks are handled
10.194 + * as follows:
10.195 + *
10.196 + * <ul>
10.197 + *
10.198 + * <li><p> When decoding, the <tt>UTF-16BE</tt> and <tt>UTF-16LE</tt>
10.199 + * charsets interpret the initial byte-order marks as a <small>ZERO-WIDTH
10.200 + * NON-BREAKING SPACE</small>; when encoding, they do not write
10.201 + * byte-order marks. </p></li>
10.202 +
10.203 + *
10.204 + * <li><p> When decoding, the <tt>UTF-16</tt> charset interprets the
10.205 + * byte-order mark at the beginning of the input stream to indicate the
10.206 + * byte-order of the stream but defaults to big-endian if there is no
10.207 + * byte-order mark; when encoding, it uses big-endian byte order and writes
10.208 + * a big-endian byte-order mark. </p></li>
10.209 + *
10.210 + * </ul>
10.211 + *
10.212 + * In any case, byte order marks occuring after the first element of an
10.213 + * input sequence are not omitted since the same code is used to represent
10.214 + * <small>ZERO-WIDTH NON-BREAKING SPACE</small>.
10.215 + *
10.216 + * <p> Every instance of the Java virtual machine has a default charset, which
10.217 + * may or may not be one of the standard charsets. The default charset is
10.218 + * determined during virtual-machine startup and typically depends upon the
10.219 + * locale and charset being used by the underlying operating system. </p>
10.220 + *
10.221 + * <p>The {@link StandardCharsets} class defines constants for each of the
10.222 + * standard charsets.
10.223 + *
10.224 + * <h4>Terminology</h4>
10.225 + *
10.226 + * <p> The name of this class is taken from the terms used in
10.227 + * <a href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC 2278</i></a>.
10.228 + * In that document a <i>charset</i> is defined as the combination of
10.229 + * one or more coded character sets and a character-encoding scheme.
10.230 + * (This definition is confusing; some other software systems define
10.231 + * <i>charset</i> as a synonym for <i>coded character set</i>.)
10.232 + *
10.233 + * <p> A <i>coded character set</i> is a mapping between a set of abstract
10.234 + * characters and a set of integers. US-ASCII, ISO 8859-1,
10.235 + * JIS X 0201, and Unicode are examples of coded character sets.
10.236 + *
10.237 + * <p> Some standards have defined a <i>character set</i> to be simply a
10.238 + * set of abstract characters without an associated assigned numbering.
10.239 + * An alphabet is an example of such a character set. However, the subtle
10.240 + * distinction between <i>character set</i> and <i>coded character set</i>
10.241 + * is rarely used in practice; the former has become a short form for the
10.242 + * latter, including in the Java API specification.
10.243 + *
10.244 + * <p> A <i>character-encoding scheme</i> is a mapping between one or more
10.245 + * coded character sets and a set of octet (eight-bit byte) sequences.
10.246 + * UTF-8, UTF-16, ISO 2022, and EUC are examples of
10.247 + * character-encoding schemes. Encoding schemes are often associated with
10.248 + * a particular coded character set; UTF-8, for example, is used only to
10.249 + * encode Unicode. Some schemes, however, are associated with multiple
10.250 + * coded character sets; EUC, for example, can be used to encode
10.251 + * characters in a variety of Asian coded character sets.
10.252 + *
10.253 + * <p> When a coded character set is used exclusively with a single
10.254 + * character-encoding scheme then the corresponding charset is usually
10.255 + * named for the coded character set; otherwise a charset is usually named
10.256 + * for the encoding scheme and, possibly, the locale of the coded
10.257 + * character sets that it supports. Hence <tt>US-ASCII</tt> is both the
10.258 + * name of a coded character set and of the charset that encodes it, while
10.259 + * <tt>EUC-JP</tt> is the name of the charset that encodes the
10.260 + * JIS X 0201, JIS X 0208, and JIS X 0212
10.261 + * coded character sets for the Japanese language.
10.262 + *
10.263 + * <p> The native character encoding of the Java programming language is
10.264 + * UTF-16. A charset in the Java platform therefore defines a mapping
10.265 + * between sequences of sixteen-bit UTF-16 code units (that is, sequences
10.266 + * of chars) and sequences of bytes. </p>
10.267 + *
10.268 + *
10.269 + * @author Mark Reinhold
10.270 + * @author JSR-51 Expert Group
10.271 + * @since 1.4
10.272 + *
10.273 + * @see CharsetDecoder
10.274 + * @see CharsetEncoder
10.275 + * @see java.nio.charset.spi.CharsetProvider
10.276 + * @see java.lang.Character
10.277 + */
10.278 +
10.279 +public abstract class Charset
10.280 + implements Comparable<Charset>
10.281 +{
10.282 +
10.283 + /* -- Static methods -- */
10.284 +
10.285 + private static volatile String bugLevel = null;
10.286 +
10.287 + static boolean atBugLevel(String bl) { // package-private
10.288 + String level = bugLevel;
10.289 + if (level == null) {
10.290 + if (!sun.misc.VM.isBooted())
10.291 + return false;
10.292 + bugLevel = level = AccessController.doPrivileged(
10.293 + new GetPropertyAction("sun.nio.cs.bugLevel", ""));
10.294 + }
10.295 + return level.equals(bl);
10.296 + }
10.297 +
10.298 + /**
10.299 + * Checks that the given string is a legal charset name. </p>
10.300 + *
10.301 + * @param s
10.302 + * A purported charset name
10.303 + *
10.304 + * @throws IllegalCharsetNameException
10.305 + * If the given name is not a legal charset name
10.306 + */
10.307 + private static void checkName(String s) {
10.308 + int n = s.length();
10.309 + if (!atBugLevel("1.4")) {
10.310 + if (n == 0)
10.311 + throw new IllegalCharsetNameException(s);
10.312 + }
10.313 + for (int i = 0; i < n; i++) {
10.314 + char c = s.charAt(i);
10.315 + if (c >= 'A' && c <= 'Z') continue;
10.316 + if (c >= 'a' && c <= 'z') continue;
10.317 + if (c >= '0' && c <= '9') continue;
10.318 + if (c == '-' && i != 0) continue;
10.319 + if (c == '+' && i != 0) continue;
10.320 + if (c == ':' && i != 0) continue;
10.321 + if (c == '_' && i != 0) continue;
10.322 + if (c == '.' && i != 0) continue;
10.323 + throw new IllegalCharsetNameException(s);
10.324 + }
10.325 + }
10.326 +
10.327 + /* The standard set of charsets */
10.328 + private static CharsetProvider standardProvider = new StandardCharsets();
10.329 +
10.330 + // Cache of the most-recently-returned charsets,
10.331 + // along with the names that were used to find them
10.332 + //
10.333 + private static volatile Object[] cache1 = null; // "Level 1" cache
10.334 + private static volatile Object[] cache2 = null; // "Level 2" cache
10.335 +
10.336 + private static void cache(String charsetName, Charset cs) {
10.337 + cache2 = cache1;
10.338 + cache1 = new Object[] { charsetName, cs };
10.339 + }
10.340 +
10.341 + // Creates an iterator that walks over the available providers, ignoring
10.342 + // those whose lookup or instantiation causes a security exception to be
10.343 + // thrown. Should be invoked with full privileges.
10.344 + //
10.345 + private static Iterator providers() {
10.346 + return new Iterator() {
10.347 +
10.348 + ClassLoader cl = ClassLoader.getSystemClassLoader();
10.349 + ServiceLoader<CharsetProvider> sl =
10.350 + ServiceLoader.load(CharsetProvider.class, cl);
10.351 + Iterator<CharsetProvider> i = sl.iterator();
10.352 +
10.353 + Object next = null;
10.354 +
10.355 + private boolean getNext() {
10.356 + while (next == null) {
10.357 + try {
10.358 + if (!i.hasNext())
10.359 + return false;
10.360 + next = i.next();
10.361 + } catch (ServiceConfigurationError sce) {
10.362 + if (sce.getCause() instanceof SecurityException) {
10.363 + // Ignore security exceptions
10.364 + continue;
10.365 + }
10.366 + throw sce;
10.367 + }
10.368 + }
10.369 + return true;
10.370 + }
10.371 +
10.372 + public boolean hasNext() {
10.373 + return getNext();
10.374 + }
10.375 +
10.376 + public Object next() {
10.377 + if (!getNext())
10.378 + throw new NoSuchElementException();
10.379 + Object n = next;
10.380 + next = null;
10.381 + return n;
10.382 + }
10.383 +
10.384 + public void remove() {
10.385 + throw new UnsupportedOperationException();
10.386 + }
10.387 +
10.388 + };
10.389 + }
10.390 +
10.391 + // Thread-local gate to prevent recursive provider lookups
10.392 + private static ThreadLocal<ThreadLocal> gate = new ThreadLocal<ThreadLocal>();
10.393 +
10.394 + private static Charset lookupViaProviders(final String charsetName) {
10.395 +
10.396 + // The runtime startup sequence looks up standard charsets as a
10.397 + // consequence of the VM's invocation of System.initializeSystemClass
10.398 + // in order to, e.g., set system properties and encode filenames. At
10.399 + // that point the application class loader has not been initialized,
10.400 + // however, so we can't look for providers because doing so will cause
10.401 + // that loader to be prematurely initialized with incomplete
10.402 + // information.
10.403 + //
10.404 + if (!sun.misc.VM.isBooted())
10.405 + return null;
10.406 +
10.407 + if (gate.get() != null)
10.408 + // Avoid recursive provider lookups
10.409 + return null;
10.410 + try {
10.411 + gate.set(gate);
10.412 +
10.413 + return AccessController.doPrivileged(
10.414 + new PrivilegedAction<Charset>() {
10.415 + public Charset run() {
10.416 + for (Iterator i = providers(); i.hasNext();) {
10.417 + CharsetProvider cp = (CharsetProvider)i.next();
10.418 + Charset cs = cp.charsetForName(charsetName);
10.419 + if (cs != null)
10.420 + return cs;
10.421 + }
10.422 + return null;
10.423 + }
10.424 + });
10.425 +
10.426 + } finally {
10.427 + gate.set(null);
10.428 + }
10.429 + }
10.430 +
10.431 + /* The extended set of charsets */
10.432 + private static Object extendedProviderLock = new Object();
10.433 + private static boolean extendedProviderProbed = false;
10.434 + private static CharsetProvider extendedProvider = null;
10.435 +
10.436 + private static void probeExtendedProvider() {
10.437 + AccessController.doPrivileged(new PrivilegedAction<Object>() {
10.438 + public Object run() {
10.439 + try {
10.440 + Class epc
10.441 + = Class.forName("sun.nio.cs.ext.ExtendedCharsets");
10.442 + extendedProvider = (CharsetProvider)epc.newInstance();
10.443 + } catch (ClassNotFoundException x) {
10.444 + // Extended charsets not available
10.445 + // (charsets.jar not present)
10.446 + } catch (InstantiationException x) {
10.447 + throw new Error(x);
10.448 + } catch (IllegalAccessException x) {
10.449 + throw new Error(x);
10.450 + }
10.451 + return null;
10.452 + }
10.453 + });
10.454 + }
10.455 +
10.456 + private static Charset lookupExtendedCharset(String charsetName) {
10.457 + CharsetProvider ecp = null;
10.458 + synchronized (extendedProviderLock) {
10.459 + if (!extendedProviderProbed) {
10.460 + probeExtendedProvider();
10.461 + extendedProviderProbed = true;
10.462 + }
10.463 + ecp = extendedProvider;
10.464 + }
10.465 + return (ecp != null) ? ecp.charsetForName(charsetName) : null;
10.466 + }
10.467 +
10.468 + private static Charset lookup(String charsetName) {
10.469 + if (charsetName == null)
10.470 + throw new IllegalArgumentException("Null charset name");
10.471 +
10.472 + Object[] a;
10.473 + if ((a = cache1) != null && charsetName.equals(a[0]))
10.474 + return (Charset)a[1];
10.475 + // We expect most programs to use one Charset repeatedly.
10.476 + // We convey a hint to this effect to the VM by putting the
10.477 + // level 1 cache miss code in a separate method.
10.478 + return lookup2(charsetName);
10.479 + }
10.480 +
10.481 + private static Charset lookup2(String charsetName) {
10.482 + Object[] a;
10.483 + if ((a = cache2) != null && charsetName.equals(a[0])) {
10.484 + cache2 = cache1;
10.485 + cache1 = a;
10.486 + return (Charset)a[1];
10.487 + }
10.488 +
10.489 + Charset cs;
10.490 + if ((cs = standardProvider.charsetForName(charsetName)) != null ||
10.491 + (cs = lookupExtendedCharset(charsetName)) != null ||
10.492 + (cs = lookupViaProviders(charsetName)) != null)
10.493 + {
10.494 + cache(charsetName, cs);
10.495 + return cs;
10.496 + }
10.497 +
10.498 + /* Only need to check the name if we didn't find a charset for it */
10.499 + checkName(charsetName);
10.500 + return null;
10.501 + }
10.502 +
10.503 + /**
10.504 + * Tells whether the named charset is supported. </p>
10.505 + *
10.506 + * @param charsetName
10.507 + * The name of the requested charset; may be either
10.508 + * a canonical name or an alias
10.509 + *
10.510 + * @return <tt>true</tt> if, and only if, support for the named charset
10.511 + * is available in the current Java virtual machine
10.512 + *
10.513 + * @throws IllegalCharsetNameException
10.514 + * If the given charset name is illegal
10.515 + *
10.516 + * @throws IllegalArgumentException
10.517 + * If the given <tt>charsetName</tt> is null
10.518 + */
10.519 + public static boolean isSupported(String charsetName) {
10.520 + return (lookup(charsetName) != null);
10.521 + }
10.522 +
10.523 + /**
10.524 + * Returns a charset object for the named charset. </p>
10.525 + *
10.526 + * @param charsetName
10.527 + * The name of the requested charset; may be either
10.528 + * a canonical name or an alias
10.529 + *
10.530 + * @return A charset object for the named charset
10.531 + *
10.532 + * @throws IllegalCharsetNameException
10.533 + * If the given charset name is illegal
10.534 + *
10.535 + * @throws IllegalArgumentException
10.536 + * If the given <tt>charsetName</tt> is null
10.537 + *
10.538 + * @throws UnsupportedCharsetException
10.539 + * If no support for the named charset is available
10.540 + * in this instance of the Java virtual machine
10.541 + */
10.542 + public static Charset forName(String charsetName) {
10.543 + Charset cs = lookup(charsetName);
10.544 + if (cs != null)
10.545 + return cs;
10.546 + throw new UnsupportedCharsetException(charsetName);
10.547 + }
10.548 +
10.549 + // Fold charsets from the given iterator into the given map, ignoring
10.550 + // charsets whose names already have entries in the map.
10.551 + //
10.552 + private static void put(Iterator<Charset> i, Map<String,Charset> m) {
10.553 + while (i.hasNext()) {
10.554 + Charset cs = i.next();
10.555 + if (!m.containsKey(cs.name()))
10.556 + m.put(cs.name(), cs);
10.557 + }
10.558 + }
10.559 +
10.560 + /**
10.561 + * Constructs a sorted map from canonical charset names to charset objects.
10.562 + *
10.563 + * <p> The map returned by this method will have one entry for each charset
10.564 + * for which support is available in the current Java virtual machine. If
10.565 + * two or more supported charsets have the same canonical name then the
10.566 + * resulting map will contain just one of them; which one it will contain
10.567 + * is not specified. </p>
10.568 + *
10.569 + * <p> The invocation of this method, and the subsequent use of the
10.570 + * resulting map, may cause time-consuming disk or network I/O operations
10.571 + * to occur. This method is provided for applications that need to
10.572 + * enumerate all of the available charsets, for example to allow user
10.573 + * charset selection. This method is not used by the {@link #forName
10.574 + * forName} method, which instead employs an efficient incremental lookup
10.575 + * algorithm.
10.576 + *
10.577 + * <p> This method may return different results at different times if new
10.578 + * charset providers are dynamically made available to the current Java
10.579 + * virtual machine. In the absence of such changes, the charsets returned
10.580 + * by this method are exactly those that can be retrieved via the {@link
10.581 + * #forName forName} method. </p>
10.582 + *
10.583 + * @return An immutable, case-insensitive map from canonical charset names
10.584 + * to charset objects
10.585 + */
10.586 + public static SortedMap<String,Charset> availableCharsets() {
10.587 + return AccessController.doPrivileged(
10.588 + new PrivilegedAction<SortedMap<String,Charset>>() {
10.589 + public SortedMap<String,Charset> run() {
10.590 + TreeMap<String,Charset> m =
10.591 + new TreeMap<String,Charset>(
10.592 + ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
10.593 + put(standardProvider.charsets(), m);
10.594 + for (Iterator i = providers(); i.hasNext();) {
10.595 + CharsetProvider cp = (CharsetProvider)i.next();
10.596 + put(cp.charsets(), m);
10.597 + }
10.598 + return Collections.unmodifiableSortedMap(m);
10.599 + }
10.600 + });
10.601 + }
10.602 +
10.603 + private static volatile Charset defaultCharset;
10.604 +
10.605 + /**
10.606 + * Returns the default charset of this Java virtual machine.
10.607 + *
10.608 + * <p> The default charset is determined during virtual-machine startup and
10.609 + * typically depends upon the locale and charset of the underlying
10.610 + * operating system.
10.611 + *
10.612 + * @return A charset object for the default charset
10.613 + *
10.614 + * @since 1.5
10.615 + */
10.616 + public static Charset defaultCharset() {
10.617 + if (defaultCharset == null) {
10.618 + synchronized (Charset.class) {
10.619 + String csn = AccessController.doPrivileged(
10.620 + new GetPropertyAction("file.encoding"));
10.621 + Charset cs = lookup(csn);
10.622 + if (cs != null)
10.623 + defaultCharset = cs;
10.624 + else
10.625 + defaultCharset = forName("UTF-8");
10.626 + }
10.627 + }
10.628 + return defaultCharset;
10.629 + }
10.630 +
10.631 +
10.632 + /* -- Instance fields and methods -- */
10.633 +
10.634 + private final String name; // tickles a bug in oldjavac
10.635 + private final String[] aliases; // tickles a bug in oldjavac
10.636 + private Set<String> aliasSet = null;
10.637 +
10.638 + /**
10.639 + * Initializes a new charset with the given canonical name and alias
10.640 + * set. </p>
10.641 + *
10.642 + * @param canonicalName
10.643 + * The canonical name of this charset
10.644 + *
10.645 + * @param aliases
10.646 + * An array of this charset's aliases, or null if it has no aliases
10.647 + *
10.648 + * @throws IllegalCharsetNameException
10.649 + * If the canonical name or any of the aliases are illegal
10.650 + */
10.651 + protected Charset(String canonicalName, String[] aliases) {
10.652 + checkName(canonicalName);
10.653 + String[] as = (aliases == null) ? new String[0] : aliases;
10.654 + for (int i = 0; i < as.length; i++)
10.655 + checkName(as[i]);
10.656 + this.name = canonicalName;
10.657 + this.aliases = as;
10.658 + }
10.659 +
10.660 + /**
10.661 + * Returns this charset's canonical name. </p>
10.662 + *
10.663 + * @return The canonical name of this charset
10.664 + */
10.665 + public final String name() {
10.666 + return name;
10.667 + }
10.668 +
10.669 + /**
10.670 + * Returns a set containing this charset's aliases. </p>
10.671 + *
10.672 + * @return An immutable set of this charset's aliases
10.673 + */
10.674 + public final Set<String> aliases() {
10.675 + if (aliasSet != null)
10.676 + return aliasSet;
10.677 + int n = aliases.length;
10.678 + HashSet<String> hs = new HashSet<String>(n);
10.679 + for (int i = 0; i < n; i++)
10.680 + hs.add(aliases[i]);
10.681 + aliasSet = Collections.unmodifiableSet(hs);
10.682 + return aliasSet;
10.683 + }
10.684 +
10.685 + /**
10.686 + * Returns this charset's human-readable name for the default locale.
10.687 + *
10.688 + * <p> The default implementation of this method simply returns this
10.689 + * charset's canonical name. Concrete subclasses of this class may
10.690 + * override this method in order to provide a localized display name. </p>
10.691 + *
10.692 + * @return The display name of this charset in the default locale
10.693 + */
10.694 + public String displayName() {
10.695 + return name;
10.696 + }
10.697 +
10.698 + /**
10.699 + * Tells whether or not this charset is registered in the <a
10.700 + * href="http://www.iana.org/assignments/character-sets">IANA Charset
10.701 + * Registry</a>. </p>
10.702 + *
10.703 + * @return <tt>true</tt> if, and only if, this charset is known by its
10.704 + * implementor to be registered with the IANA
10.705 + */
10.706 + public final boolean isRegistered() {
10.707 + return !name.startsWith("X-") && !name.startsWith("x-");
10.708 + }
10.709 +
10.710 + /**
10.711 + * Returns this charset's human-readable name for the given locale.
10.712 + *
10.713 + * <p> The default implementation of this method simply returns this
10.714 + * charset's canonical name. Concrete subclasses of this class may
10.715 + * override this method in order to provide a localized display name. </p>
10.716 + *
10.717 + * @param locale
10.718 + * The locale for which the display name is to be retrieved
10.719 + *
10.720 + * @return The display name of this charset in the given locale
10.721 + */
10.722 + public String displayName(Locale locale) {
10.723 + return name;
10.724 + }
10.725 +
10.726 + /**
10.727 + * Tells whether or not this charset contains the given charset.
10.728 + *
10.729 + * <p> A charset <i>C</i> is said to <i>contain</i> a charset <i>D</i> if,
10.730 + * and only if, every character representable in <i>D</i> is also
10.731 + * representable in <i>C</i>. If this relationship holds then it is
10.732 + * guaranteed that every string that can be encoded in <i>D</i> can also be
10.733 + * encoded in <i>C</i> without performing any replacements.
10.734 + *
10.735 + * <p> That <i>C</i> contains <i>D</i> does not imply that each character
10.736 + * representable in <i>C</i> by a particular byte sequence is represented
10.737 + * in <i>D</i> by the same byte sequence, although sometimes this is the
10.738 + * case.
10.739 + *
10.740 + * <p> Every charset contains itself.
10.741 + *
10.742 + * <p> This method computes an approximation of the containment relation:
10.743 + * If it returns <tt>true</tt> then the given charset is known to be
10.744 + * contained by this charset; if it returns <tt>false</tt>, however, then
10.745 + * it is not necessarily the case that the given charset is not contained
10.746 + * in this charset.
10.747 + *
10.748 + * @return <tt>true</tt> if the given charset is contained in this charset
10.749 + */
10.750 + public abstract boolean contains(Charset cs);
10.751 +
10.752 + /**
10.753 + * Constructs a new decoder for this charset. </p>
10.754 + *
10.755 + * @return A new decoder for this charset
10.756 + */
10.757 + public abstract CharsetDecoder newDecoder();
10.758 +
10.759 + /**
10.760 + * Constructs a new encoder for this charset. </p>
10.761 + *
10.762 + * @return A new encoder for this charset
10.763 + *
10.764 + * @throws UnsupportedOperationException
10.765 + * If this charset does not support encoding
10.766 + */
10.767 + public abstract CharsetEncoder newEncoder();
10.768 +
10.769 + /**
10.770 + * Tells whether or not this charset supports encoding.
10.771 + *
10.772 + * <p> Nearly all charsets support encoding. The primary exceptions are
10.773 + * special-purpose <i>auto-detect</i> charsets whose decoders can determine
10.774 + * which of several possible encoding schemes is in use by examining the
10.775 + * input byte sequence. Such charsets do not support encoding because
10.776 + * there is no way to determine which encoding should be used on output.
10.777 + * Implementations of such charsets should override this method to return
10.778 + * <tt>false</tt>. </p>
10.779 + *
10.780 + * @return <tt>true</tt> if, and only if, this charset supports encoding
10.781 + */
10.782 + public boolean canEncode() {
10.783 + return true;
10.784 + }
10.785 +
10.786 + /**
10.787 + * Convenience method that decodes bytes in this charset into Unicode
10.788 + * characters.
10.789 + *
10.790 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
10.791 + * same result as the expression
10.792 + *
10.793 + * <pre>
10.794 + * cs.newDecoder()
10.795 + * .onMalformedInput(CodingErrorAction.REPLACE)
10.796 + * .onUnmappableCharacter(CodingErrorAction.REPLACE)
10.797 + * .decode(bb); </pre>
10.798 + *
10.799 + * except that it is potentially more efficient because it can cache
10.800 + * decoders between successive invocations.
10.801 + *
10.802 + * <p> This method always replaces malformed-input and unmappable-character
10.803 + * sequences with this charset's default replacement byte array. In order
10.804 + * to detect such sequences, use the {@link
10.805 + * CharsetDecoder#decode(java.nio.ByteBuffer)} method directly. </p>
10.806 + *
10.807 + * @param bb The byte buffer to be decoded
10.808 + *
10.809 + * @return A char buffer containing the decoded characters
10.810 + */
10.811 + public final CharBuffer decode(ByteBuffer bb) {
10.812 + try {
10.813 + return ThreadLocalCoders.decoderFor(this)
10.814 + .onMalformedInput(CodingErrorAction.REPLACE)
10.815 + .onUnmappableCharacter(CodingErrorAction.REPLACE)
10.816 + .decode(bb);
10.817 + } catch (CharacterCodingException x) {
10.818 + throw new Error(x); // Can't happen
10.819 + }
10.820 + }
10.821 +
10.822 + /**
10.823 + * Convenience method that encodes Unicode characters into bytes in this
10.824 + * charset.
10.825 + *
10.826 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
10.827 + * same result as the expression
10.828 + *
10.829 + * <pre>
10.830 + * cs.newEncoder()
10.831 + * .onMalformedInput(CodingErrorAction.REPLACE)
10.832 + * .onUnmappableCharacter(CodingErrorAction.REPLACE)
10.833 + * .encode(bb); </pre>
10.834 + *
10.835 + * except that it is potentially more efficient because it can cache
10.836 + * encoders between successive invocations.
10.837 + *
10.838 + * <p> This method always replaces malformed-input and unmappable-character
10.839 + * sequences with this charset's default replacement string. In order to
10.840 + * detect such sequences, use the {@link
10.841 + * CharsetEncoder#encode(java.nio.CharBuffer)} method directly. </p>
10.842 + *
10.843 + * @param cb The char buffer to be encoded
10.844 + *
10.845 + * @return A byte buffer containing the encoded characters
10.846 + */
10.847 + public final ByteBuffer encode(CharBuffer cb) {
10.848 + try {
10.849 + return ThreadLocalCoders.encoderFor(this)
10.850 + .onMalformedInput(CodingErrorAction.REPLACE)
10.851 + .onUnmappableCharacter(CodingErrorAction.REPLACE)
10.852 + .encode(cb);
10.853 + } catch (CharacterCodingException x) {
10.854 + throw new Error(x); // Can't happen
10.855 + }
10.856 + }
10.857 +
10.858 + /**
10.859 + * Convenience method that encodes a string into bytes in this charset.
10.860 + *
10.861 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
10.862 + * same result as the expression
10.863 + *
10.864 + * <pre>
10.865 + * cs.encode(CharBuffer.wrap(s)); </pre>
10.866 + *
10.867 + * @param str The string to be encoded
10.868 + *
10.869 + * @return A byte buffer containing the encoded characters
10.870 + */
10.871 + public final ByteBuffer encode(String str) {
10.872 + return encode(CharBuffer.wrap(str));
10.873 + }
10.874 +
10.875 + /**
10.876 + * Compares this charset to another.
10.877 + *
10.878 + * <p> Charsets are ordered by their canonical names, without regard to
10.879 + * case. </p>
10.880 + *
10.881 + * @param that
10.882 + * The charset to which this charset is to be compared
10.883 + *
10.884 + * @return A negative integer, zero, or a positive integer as this charset
10.885 + * is less than, equal to, or greater than the specified charset
10.886 + */
10.887 + public final int compareTo(Charset that) {
10.888 + return (name().compareToIgnoreCase(that.name()));
10.889 + }
10.890 +
10.891 + /**
10.892 + * Computes a hashcode for this charset. </p>
10.893 + *
10.894 + * @return An integer hashcode
10.895 + */
10.896 + public final int hashCode() {
10.897 + return name().hashCode();
10.898 + }
10.899 +
10.900 + /**
10.901 + * Tells whether or not this object is equal to another.
10.902 + *
10.903 + * <p> Two charsets are equal if, and only if, they have the same canonical
10.904 + * names. A charset is never equal to any other type of object. </p>
10.905 + *
10.906 + * @return <tt>true</tt> if, and only if, this charset is equal to the
10.907 + * given object
10.908 + */
10.909 + public final boolean equals(Object ob) {
10.910 + if (!(ob instanceof Charset))
10.911 + return false;
10.912 + if (this == ob)
10.913 + return true;
10.914 + return name.equals(((Charset)ob).name());
10.915 + }
10.916 +
10.917 + /**
10.918 + * Returns a string describing this charset. </p>
10.919 + *
10.920 + * @return A string describing this charset
10.921 + */
10.922 + public final String toString() {
10.923 + return name();
10.924 + }
10.925 +
10.926 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetDecoder.java Thu Oct 03 15:40:35 2013 +0200
11.3 @@ -0,0 +1,972 @@
11.4 +/*
11.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
11.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
11.7 + *
11.8 + *
11.9 + *
11.10 + *
11.11 + *
11.12 + *
11.13 + *
11.14 + *
11.15 + *
11.16 + *
11.17 + *
11.18 + *
11.19 + *
11.20 + *
11.21 + *
11.22 + *
11.23 + *
11.24 + *
11.25 + *
11.26 + *
11.27 + */
11.28 +
11.29 +// -- This file was mechanically generated: Do not edit! -- //
11.30 +
11.31 +package java.nio.charset;
11.32 +
11.33 +import java.nio.Buffer;
11.34 +import java.nio.ByteBuffer;
11.35 +import java.nio.CharBuffer;
11.36 +import java.nio.BufferOverflowException;
11.37 +import java.nio.BufferUnderflowException;
11.38 +import java.lang.ref.WeakReference;
11.39 +import java.nio.charset.CoderMalfunctionError; // javadoc
11.40 +
11.41 +
11.42 +/**
11.43 + * An engine that can transform a sequence of bytes in a specific charset into a sequence of
11.44 + * sixteen-bit Unicode characters.
11.45 + *
11.46 + * <a name="steps">
11.47 + *
11.48 + * <p> The input byte sequence is provided in a byte buffer or a series
11.49 + * of such buffers. The output character sequence is written to a character buffer
11.50 + * or a series of such buffers. A decoder should always be used by making
11.51 + * the following sequence of method invocations, hereinafter referred to as a
11.52 + * <i>decoding operation</i>:
11.53 + *
11.54 + * <ol>
11.55 + *
11.56 + * <li><p> Reset the decoder via the {@link #reset reset} method, unless it
11.57 + * has not been used before; </p></li>
11.58 + *
11.59 + * <li><p> Invoke the {@link #decode decode} method zero or more times, as
11.60 + * long as additional input may be available, passing <tt>false</tt> for the
11.61 + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
11.62 + * output buffer between invocations; </p></li>
11.63 + *
11.64 + * <li><p> Invoke the {@link #decode decode} method one final time, passing
11.65 + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
11.66 + *
11.67 + * <li><p> Invoke the {@link #flush flush} method so that the decoder can
11.68 + * flush any internal state to the output buffer. </p></li>
11.69 + *
11.70 + * </ol>
11.71 + *
11.72 + * Each invocation of the {@link #decode decode} method will decode as many
11.73 + * bytes as possible from the input buffer, writing the resulting characters
11.74 + * to the output buffer. The {@link #decode decode} method returns when more
11.75 + * input is required, when there is not enough room in the output buffer, or
11.76 + * when a decoding error has occurred. In each case a {@link CoderResult}
11.77 + * object is returned to describe the reason for termination. An invoker can
11.78 + * examine this object and fill the input buffer, flush the output buffer, or
11.79 + * attempt to recover from a decoding error, as appropriate, and try again.
11.80 + *
11.81 + * <a name="ce">
11.82 + *
11.83 + * <p> There are two general types of decoding errors. If the input byte
11.84 + * sequence is not legal for this charset then the input is considered <i>malformed</i>. If
11.85 + * the input byte sequence is legal but cannot be mapped to a valid
11.86 + * Unicode character then an <i>unmappable character</i> has been encountered.
11.87 + *
11.88 + * <a name="cae">
11.89 + *
11.90 + * <p> How a decoding error is handled depends upon the action requested for
11.91 + * that type of error, which is described by an instance of the {@link
11.92 + * CodingErrorAction} class. The possible error actions are to {@link
11.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
11.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
11.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
11.96 + * </code>replace<code>} the erroneous input with the current value of the
11.97 + * replacement string. The replacement
11.98 + *
11.99 +
11.100 +
11.101 +
11.102 +
11.103 +
11.104 + * has the initial value <tt>"\uFFFD"</tt>;
11.105 +
11.106 + *
11.107 + * its value may be changed via the {@link #replaceWith(java.lang.String)
11.108 + * replaceWith} method.
11.109 + *
11.110 + * <p> The default action for malformed-input and unmappable-character errors
11.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
11.112 + * malformed-input error action may be changed via the {@link
11.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
11.114 + * unmappable-character action may be changed via the {@link
11.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
11.116 + *
11.117 + * <p> This class is designed to handle many of the details of the decoding
11.118 + * process, including the implementation of error actions. A decoder for a
11.119 + * specific charset, which is a concrete subclass of this class, need only
11.120 + * implement the abstract {@link #decodeLoop decodeLoop} method, which
11.121 + * encapsulates the basic decoding loop. A subclass that maintains internal
11.122 + * state should, additionally, override the {@link #implFlush implFlush} and
11.123 + * {@link #implReset implReset} methods.
11.124 + *
11.125 + * <p> Instances of this class are not safe for use by multiple concurrent
11.126 + * threads. </p>
11.127 + *
11.128 + *
11.129 + * @author Mark Reinhold
11.130 + * @author JSR-51 Expert Group
11.131 + * @since 1.4
11.132 + *
11.133 + * @see ByteBuffer
11.134 + * @see CharBuffer
11.135 + * @see Charset
11.136 + * @see CharsetEncoder
11.137 + */
11.138 +
11.139 +public abstract class CharsetDecoder {
11.140 +
11.141 + private final Charset charset;
11.142 + private final float averageCharsPerByte;
11.143 + private final float maxCharsPerByte;
11.144 +
11.145 + private String replacement;
11.146 + private CodingErrorAction malformedInputAction
11.147 + = CodingErrorAction.REPORT;
11.148 + private CodingErrorAction unmappableCharacterAction
11.149 + = CodingErrorAction.REPORT;
11.150 +
11.151 + // Internal states
11.152 + //
11.153 + private static final int ST_RESET = 0;
11.154 + private static final int ST_CODING = 1;
11.155 + private static final int ST_END = 2;
11.156 + private static final int ST_FLUSHED = 3;
11.157 +
11.158 + private int state = ST_RESET;
11.159 +
11.160 + private static String stateNames[]
11.161 + = { "RESET", "CODING", "CODING_END", "FLUSHED" };
11.162 +
11.163 +
11.164 + /**
11.165 + * Initializes a new decoder. The new decoder will have the given
11.166 + * chars-per-byte and replacement values. </p>
11.167 + *
11.168 + * @param averageCharsPerByte
11.169 + * A positive float value indicating the expected number of
11.170 + * characters that will be produced for each input byte
11.171 + *
11.172 + * @param maxCharsPerByte
11.173 + * A positive float value indicating the maximum number of
11.174 + * characters that will be produced for each input byte
11.175 + *
11.176 + * @param replacement
11.177 + * The initial replacement; must not be <tt>null</tt>, must have
11.178 + * non-zero length, must not be longer than maxCharsPerByte,
11.179 + * and must be {@link #isLegalReplacement </code>legal<code>}
11.180 + *
11.181 + * @throws IllegalArgumentException
11.182 + * If the preconditions on the parameters do not hold
11.183 + */
11.184 + private
11.185 + CharsetDecoder(Charset cs,
11.186 + float averageCharsPerByte,
11.187 + float maxCharsPerByte,
11.188 + String replacement)
11.189 + {
11.190 + this.charset = cs;
11.191 + if (averageCharsPerByte <= 0.0f)
11.192 + throw new IllegalArgumentException("Non-positive "
11.193 + + "averageCharsPerByte");
11.194 + if (maxCharsPerByte <= 0.0f)
11.195 + throw new IllegalArgumentException("Non-positive "
11.196 + + "maxCharsPerByte");
11.197 + if (!Charset.atBugLevel("1.4")) {
11.198 + if (averageCharsPerByte > maxCharsPerByte)
11.199 + throw new IllegalArgumentException("averageCharsPerByte"
11.200 + + " exceeds "
11.201 + + "maxCharsPerByte");
11.202 + }
11.203 + this.replacement = replacement;
11.204 + this.averageCharsPerByte = averageCharsPerByte;
11.205 + this.maxCharsPerByte = maxCharsPerByte;
11.206 + replaceWith(replacement);
11.207 + }
11.208 +
11.209 + /**
11.210 + * Initializes a new decoder. The new decoder will have the given
11.211 + * chars-per-byte values and its replacement will be the
11.212 + * string <tt>"\uFFFD"</tt>. </p>
11.213 + *
11.214 + * @param averageCharsPerByte
11.215 + * A positive float value indicating the expected number of
11.216 + * characters that will be produced for each input byte
11.217 + *
11.218 + * @param maxCharsPerByte
11.219 + * A positive float value indicating the maximum number of
11.220 + * characters that will be produced for each input byte
11.221 + *
11.222 + * @throws IllegalArgumentException
11.223 + * If the preconditions on the parameters do not hold
11.224 + */
11.225 + protected CharsetDecoder(Charset cs,
11.226 + float averageCharsPerByte,
11.227 + float maxCharsPerByte)
11.228 + {
11.229 + this(cs,
11.230 + averageCharsPerByte, maxCharsPerByte,
11.231 + "\uFFFD");
11.232 + }
11.233 +
11.234 + /**
11.235 + * Returns the charset that created this decoder. </p>
11.236 + *
11.237 + * @return This decoder's charset
11.238 + */
11.239 + public final Charset charset() {
11.240 + return charset;
11.241 + }
11.242 +
11.243 + /**
11.244 + * Returns this decoder's replacement value. </p>
11.245 + *
11.246 + * @return This decoder's current replacement,
11.247 + * which is never <tt>null</tt> and is never empty
11.248 + */
11.249 + public final String replacement() {
11.250 + return replacement;
11.251 + }
11.252 +
11.253 + /**
11.254 + * Changes this decoder's replacement value.
11.255 + *
11.256 + * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
11.257 + * method, passing the new replacement, after checking that the new
11.258 + * replacement is acceptable. </p>
11.259 + *
11.260 + * @param newReplacement
11.261 + *
11.262 +
11.263 + * The new replacement; must not be <tt>null</tt>
11.264 + * and must have non-zero length
11.265 +
11.266 +
11.267 +
11.268 +
11.269 +
11.270 +
11.271 +
11.272 + *
11.273 + * @return This decoder
11.274 + *
11.275 + * @throws IllegalArgumentException
11.276 + * If the preconditions on the parameter do not hold
11.277 + */
11.278 + public final CharsetDecoder replaceWith(String newReplacement) {
11.279 + if (newReplacement == null)
11.280 + throw new IllegalArgumentException("Null replacement");
11.281 + int len = newReplacement.length();
11.282 + if (len == 0)
11.283 + throw new IllegalArgumentException("Empty replacement");
11.284 + if (len > maxCharsPerByte)
11.285 + throw new IllegalArgumentException("Replacement too long");
11.286 +
11.287 +
11.288 +
11.289 +
11.290 + this.replacement = newReplacement;
11.291 + implReplaceWith(newReplacement);
11.292 + return this;
11.293 + }
11.294 +
11.295 + /**
11.296 + * Reports a change to this decoder's replacement value.
11.297 + *
11.298 + * <p> The default implementation of this method does nothing. This method
11.299 + * should be overridden by decoders that require notification of changes to
11.300 + * the replacement. </p>
11.301 + *
11.302 + * @param newReplacement
11.303 + */
11.304 + protected void implReplaceWith(String newReplacement) {
11.305 + }
11.306 +
11.307 +
11.308 +
11.309 +
11.310 +
11.311 +
11.312 +
11.313 +
11.314 +
11.315 +
11.316 +
11.317 +
11.318 +
11.319 +
11.320 +
11.321 +
11.322 +
11.323 +
11.324 +
11.325 +
11.326 +
11.327 +
11.328 +
11.329 +
11.330 +
11.331 +
11.332 +
11.333 +
11.334 +
11.335 +
11.336 +
11.337 +
11.338 +
11.339 +
11.340 +
11.341 +
11.342 +
11.343 +
11.344 +
11.345 +
11.346 +
11.347 + /**
11.348 + * Returns this decoder's current action for malformed-input errors. </p>
11.349 + *
11.350 + * @return The current malformed-input action, which is never <tt>null</tt>
11.351 + */
11.352 + public CodingErrorAction malformedInputAction() {
11.353 + return malformedInputAction;
11.354 + }
11.355 +
11.356 + /**
11.357 + * Changes this decoder's action for malformed-input errors. </p>
11.358 + *
11.359 + * <p> This method invokes the {@link #implOnMalformedInput
11.360 + * implOnMalformedInput} method, passing the new action. </p>
11.361 + *
11.362 + * @param newAction The new action; must not be <tt>null</tt>
11.363 + *
11.364 + * @return This decoder
11.365 + *
11.366 + * @throws IllegalArgumentException
11.367 + * If the precondition on the parameter does not hold
11.368 + */
11.369 + public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
11.370 + if (newAction == null)
11.371 + throw new IllegalArgumentException("Null action");
11.372 + malformedInputAction = newAction;
11.373 + implOnMalformedInput(newAction);
11.374 + return this;
11.375 + }
11.376 +
11.377 + /**
11.378 + * Reports a change to this decoder's malformed-input action.
11.379 + *
11.380 + * <p> The default implementation of this method does nothing. This method
11.381 + * should be overridden by decoders that require notification of changes to
11.382 + * the malformed-input action. </p>
11.383 + */
11.384 + protected void implOnMalformedInput(CodingErrorAction newAction) { }
11.385 +
11.386 + /**
11.387 + * Returns this decoder's current action for unmappable-character errors.
11.388 + * </p>
11.389 + *
11.390 + * @return The current unmappable-character action, which is never
11.391 + * <tt>null</tt>
11.392 + */
11.393 + public CodingErrorAction unmappableCharacterAction() {
11.394 + return unmappableCharacterAction;
11.395 + }
11.396 +
11.397 + /**
11.398 + * Changes this decoder's action for unmappable-character errors.
11.399 + *
11.400 + * <p> This method invokes the {@link #implOnUnmappableCharacter
11.401 + * implOnUnmappableCharacter} method, passing the new action. </p>
11.402 + *
11.403 + * @param newAction The new action; must not be <tt>null</tt>
11.404 + *
11.405 + * @return This decoder
11.406 + *
11.407 + * @throws IllegalArgumentException
11.408 + * If the precondition on the parameter does not hold
11.409 + */
11.410 + public final CharsetDecoder onUnmappableCharacter(CodingErrorAction
11.411 + newAction)
11.412 + {
11.413 + if (newAction == null)
11.414 + throw new IllegalArgumentException("Null action");
11.415 + unmappableCharacterAction = newAction;
11.416 + implOnUnmappableCharacter(newAction);
11.417 + return this;
11.418 + }
11.419 +
11.420 + /**
11.421 + * Reports a change to this decoder's unmappable-character action.
11.422 + *
11.423 + * <p> The default implementation of this method does nothing. This method
11.424 + * should be overridden by decoders that require notification of changes to
11.425 + * the unmappable-character action. </p>
11.426 + */
11.427 + protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
11.428 +
11.429 + /**
11.430 + * Returns the average number of characters that will be produced for each
11.431 + * byte of input. This heuristic value may be used to estimate the size
11.432 + * of the output buffer required for a given input sequence. </p>
11.433 + *
11.434 + * @return The average number of characters produced
11.435 + * per byte of input
11.436 + */
11.437 + public final float averageCharsPerByte() {
11.438 + return averageCharsPerByte;
11.439 + }
11.440 +
11.441 + /**
11.442 + * Returns the maximum number of characters that will be produced for each
11.443 + * byte of input. This value may be used to compute the worst-case size
11.444 + * of the output buffer required for a given input sequence. </p>
11.445 + *
11.446 + * @return The maximum number of characters that will be produced per
11.447 + * byte of input
11.448 + */
11.449 + public final float maxCharsPerByte() {
11.450 + return maxCharsPerByte;
11.451 + }
11.452 +
11.453 + /**
11.454 + * Decodes as many bytes as possible from the given input buffer,
11.455 + * writing the results to the given output buffer.
11.456 + *
11.457 + * <p> The buffers are read from, and written to, starting at their current
11.458 + * positions. At most {@link Buffer#remaining in.remaining()} bytes
11.459 + * will be read and at most {@link Buffer#remaining out.remaining()}
11.460 + * characters will be written. The buffers' positions will be advanced to
11.461 + * reflect the bytes read and the characters written, but their marks and
11.462 + * limits will not be modified.
11.463 + *
11.464 + * <p> In addition to reading bytes from the input buffer and writing
11.465 + * characters to the output buffer, this method returns a {@link CoderResult}
11.466 + * object to describe its reason for termination:
11.467 + *
11.468 + * <ul>
11.469 + *
11.470 + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
11.471 + * input buffer as possible has been decoded. If there is no further
11.472 + * input then the invoker can proceed to the next step of the
11.473 + * <a href="#steps">decoding operation</a>. Otherwise this method
11.474 + * should be invoked again with further input. </p></li>
11.475 + *
11.476 + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is
11.477 + * insufficient space in the output buffer to decode any more bytes.
11.478 + * This method should be invoked again with an output buffer that has
11.479 + * more {@linkplain Buffer#remaining remaining} characters. This is
11.480 + * typically done by draining any decoded characters from the output
11.481 + * buffer. </p></li>
11.482 + *
11.483 + * <li><p> A {@link CoderResult#malformedForLength
11.484 + * </code>malformed-input<code>} result indicates that a malformed-input
11.485 + * error has been detected. The malformed bytes begin at the input
11.486 + * buffer's (possibly incremented) position; the number of malformed
11.487 + * bytes may be determined by invoking the result object's {@link
11.488 + * CoderResult#length() length} method. This case applies only if the
11.489 + * {@link #onMalformedInput </code>malformed action<code>} of this decoder
11.490 + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
11.491 + * will be ignored or replaced, as requested. </p></li>
11.492 + *
11.493 + * <li><p> An {@link CoderResult#unmappableForLength
11.494 + * </code>unmappable-character<code>} result indicates that an
11.495 + * unmappable-character error has been detected. The bytes that
11.496 + * decode the unmappable character begin at the input buffer's (possibly
11.497 + * incremented) position; the number of such bytes may be determined
11.498 + * by invoking the result object's {@link CoderResult#length() length}
11.499 + * method. This case applies only if the {@link #onUnmappableCharacter
11.500 + * </code>unmappable action<code>} of this decoder is {@link
11.501 + * CodingErrorAction#REPORT}; otherwise the unmappable character will be
11.502 + * ignored or replaced, as requested. </p></li>
11.503 + *
11.504 + * </ul>
11.505 + *
11.506 + * In any case, if this method is to be reinvoked in the same decoding
11.507 + * operation then care should be taken to preserve any bytes remaining
11.508 + * in the input buffer so that they are available to the next invocation.
11.509 + *
11.510 + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
11.511 + * the invoker can provide further input beyond that contained in the given
11.512 + * input buffer. If there is a possibility of providing additional input
11.513 + * then the invoker should pass <tt>false</tt> for this parameter; if there
11.514 + * is no possibility of providing further input then the invoker should
11.515 + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
11.516 + * common, to pass <tt>false</tt> in one invocation and later discover that
11.517 + * no further input was actually available. It is critical, however, that
11.518 + * the final invocation of this method in a sequence of invocations always
11.519 + * pass <tt>true</tt> so that any remaining undecoded input will be treated
11.520 + * as being malformed.
11.521 + *
11.522 + * <p> This method works by invoking the {@link #decodeLoop decodeLoop}
11.523 + * method, interpreting its results, handling error conditions, and
11.524 + * reinvoking it as necessary. </p>
11.525 + *
11.526 + *
11.527 + * @param in
11.528 + * The input byte buffer
11.529 + *
11.530 + * @param out
11.531 + * The output character buffer
11.532 + *
11.533 + * @param endOfInput
11.534 + * <tt>true</tt> if, and only if, the invoker can provide no
11.535 + * additional input bytes beyond those in the given buffer
11.536 + *
11.537 + * @return A coder-result object describing the reason for termination
11.538 + *
11.539 + * @throws IllegalStateException
11.540 + * If a decoding operation is already in progress and the previous
11.541 + * step was an invocation neither of the {@link #reset reset}
11.542 + * method, nor of this method with a value of <tt>false</tt> for
11.543 + * the <tt>endOfInput</tt> parameter, nor of this method with a
11.544 + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
11.545 + * but a return value indicating an incomplete decoding operation
11.546 + *
11.547 + * @throws CoderMalfunctionError
11.548 + * If an invocation of the decodeLoop method threw
11.549 + * an unexpected exception
11.550 + */
11.551 + public final CoderResult decode(ByteBuffer in, CharBuffer out,
11.552 + boolean endOfInput)
11.553 + {
11.554 + int newState = endOfInput ? ST_END : ST_CODING;
11.555 + if ((state != ST_RESET) && (state != ST_CODING)
11.556 + && !(endOfInput && (state == ST_END)))
11.557 + throwIllegalStateException(state, newState);
11.558 + state = newState;
11.559 +
11.560 + for (;;) {
11.561 +
11.562 + CoderResult cr;
11.563 + try {
11.564 + cr = decodeLoop(in, out);
11.565 + } catch (BufferUnderflowException x) {
11.566 + throw new CoderMalfunctionError(x);
11.567 + } catch (BufferOverflowException x) {
11.568 + throw new CoderMalfunctionError(x);
11.569 + }
11.570 +
11.571 + if (cr.isOverflow())
11.572 + return cr;
11.573 +
11.574 + if (cr.isUnderflow()) {
11.575 + if (endOfInput && in.hasRemaining()) {
11.576 + cr = CoderResult.malformedForLength(in.remaining());
11.577 + // Fall through to malformed-input case
11.578 + } else {
11.579 + return cr;
11.580 + }
11.581 + }
11.582 +
11.583 + CodingErrorAction action = null;
11.584 + if (cr.isMalformed())
11.585 + action = malformedInputAction;
11.586 + else if (cr.isUnmappable())
11.587 + action = unmappableCharacterAction;
11.588 + else
11.589 + assert false : cr.toString();
11.590 +
11.591 + if (action == CodingErrorAction.REPORT)
11.592 + return cr;
11.593 +
11.594 + if (action == CodingErrorAction.REPLACE) {
11.595 + if (out.remaining() < replacement.length())
11.596 + return CoderResult.OVERFLOW;
11.597 + out.put(replacement);
11.598 + }
11.599 +
11.600 + if ((action == CodingErrorAction.IGNORE)
11.601 + || (action == CodingErrorAction.REPLACE)) {
11.602 + // Skip erroneous input either way
11.603 + in.position(in.position() + cr.length());
11.604 + continue;
11.605 + }
11.606 +
11.607 + assert false;
11.608 + }
11.609 +
11.610 + }
11.611 +
11.612 + /**
11.613 + * Flushes this decoder.
11.614 + *
11.615 + * <p> Some decoders maintain internal state and may need to write some
11.616 + * final characters to the output buffer once the overall input sequence has
11.617 + * been read.
11.618 + *
11.619 + * <p> Any additional output is written to the output buffer beginning at
11.620 + * its current position. At most {@link Buffer#remaining out.remaining()}
11.621 + * characters will be written. The buffer's position will be advanced
11.622 + * appropriately, but its mark and limit will not be modified.
11.623 + *
11.624 + * <p> If this method completes successfully then it returns {@link
11.625 + * CoderResult#UNDERFLOW}. If there is insufficient room in the output
11.626 + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
11.627 + * then this method must be invoked again, with an output buffer that has
11.628 + * more room, in order to complete the current <a href="#steps">decoding
11.629 + * operation</a>.
11.630 + *
11.631 + * <p> If this decoder has already been flushed then invoking this method
11.632 + * has no effect.
11.633 + *
11.634 + * <p> This method invokes the {@link #implFlush implFlush} method to
11.635 + * perform the actual flushing operation. </p>
11.636 + *
11.637 + * @param out
11.638 + * The output character buffer
11.639 + *
11.640 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
11.641 + * {@link CoderResult#OVERFLOW}
11.642 + *
11.643 + * @throws IllegalStateException
11.644 + * If the previous step of the current decoding operation was an
11.645 + * invocation neither of the {@link #flush flush} method nor of
11.646 + * the three-argument {@link
11.647 + * #decode(ByteBuffer,CharBuffer,boolean) decode} method
11.648 + * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
11.649 + * parameter
11.650 + */
11.651 + public final CoderResult flush(CharBuffer out) {
11.652 + if (state == ST_END) {
11.653 + CoderResult cr = implFlush(out);
11.654 + if (cr.isUnderflow())
11.655 + state = ST_FLUSHED;
11.656 + return cr;
11.657 + }
11.658 +
11.659 + if (state != ST_FLUSHED)
11.660 + throwIllegalStateException(state, ST_FLUSHED);
11.661 +
11.662 + return CoderResult.UNDERFLOW; // Already flushed
11.663 + }
11.664 +
11.665 + /**
11.666 + * Flushes this decoder.
11.667 + *
11.668 + * <p> The default implementation of this method does nothing, and always
11.669 + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
11.670 + * by decoders that may need to write final characters to the output buffer
11.671 + * once the entire input sequence has been read. </p>
11.672 + *
11.673 + * @param out
11.674 + * The output character buffer
11.675 + *
11.676 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
11.677 + * {@link CoderResult#OVERFLOW}
11.678 + */
11.679 + protected CoderResult implFlush(CharBuffer out) {
11.680 + return CoderResult.UNDERFLOW;
11.681 + }
11.682 +
11.683 + /**
11.684 + * Resets this decoder, clearing any internal state.
11.685 + *
11.686 + * <p> This method resets charset-independent state and also invokes the
11.687 + * {@link #implReset() implReset} method in order to perform any
11.688 + * charset-specific reset actions. </p>
11.689 + *
11.690 + * @return This decoder
11.691 + *
11.692 + */
11.693 + public final CharsetDecoder reset() {
11.694 + implReset();
11.695 + state = ST_RESET;
11.696 + return this;
11.697 + }
11.698 +
11.699 + /**
11.700 + * Resets this decoder, clearing any charset-specific internal state.
11.701 + *
11.702 + * <p> The default implementation of this method does nothing. This method
11.703 + * should be overridden by decoders that maintain internal state. </p>
11.704 + */
11.705 + protected void implReset() { }
11.706 +
11.707 + /**
11.708 + * Decodes one or more bytes into one or more characters.
11.709 + *
11.710 + * <p> This method encapsulates the basic decoding loop, decoding as many
11.711 + * bytes as possible until it either runs out of input, runs out of room
11.712 + * in the output buffer, or encounters a decoding error. This method is
11.713 + * invoked by the {@link #decode decode} method, which handles result
11.714 + * interpretation and error recovery.
11.715 + *
11.716 + * <p> The buffers are read from, and written to, starting at their current
11.717 + * positions. At most {@link Buffer#remaining in.remaining()} bytes
11.718 + * will be read, and at most {@link Buffer#remaining out.remaining()}
11.719 + * characters will be written. The buffers' positions will be advanced to
11.720 + * reflect the bytes read and the characters written, but their marks and
11.721 + * limits will not be modified.
11.722 + *
11.723 + * <p> This method returns a {@link CoderResult} object to describe its
11.724 + * reason for termination, in the same manner as the {@link #decode decode}
11.725 + * method. Most implementations of this method will handle decoding errors
11.726 + * by returning an appropriate result object for interpretation by the
11.727 + * {@link #decode decode} method. An optimized implementation may instead
11.728 + * examine the relevant error action and implement that action itself.
11.729 + *
11.730 + * <p> An implementation of this method may perform arbitrary lookahead by
11.731 + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
11.732 + * input. </p>
11.733 + *
11.734 + * @param in
11.735 + * The input byte buffer
11.736 + *
11.737 + * @param out
11.738 + * The output character buffer
11.739 + *
11.740 + * @return A coder-result object describing the reason for termination
11.741 + */
11.742 + protected abstract CoderResult decodeLoop(ByteBuffer in,
11.743 + CharBuffer out);
11.744 +
11.745 + /**
11.746 + * Convenience method that decodes the remaining content of a single input
11.747 + * byte buffer into a newly-allocated character buffer.
11.748 + *
11.749 + * <p> This method implements an entire <a href="#steps">decoding
11.750 + * operation</a>; that is, it resets this decoder, then it decodes the
11.751 + * bytes in the given byte buffer, and finally it flushes this
11.752 + * decoder. This method should therefore not be invoked if a decoding
11.753 + * operation is already in progress. </p>
11.754 + *
11.755 + * @param in
11.756 + * The input byte buffer
11.757 + *
11.758 + * @return A newly-allocated character buffer containing the result of the
11.759 + * decoding operation. The buffer's position will be zero and its
11.760 + * limit will follow the last character written.
11.761 + *
11.762 + * @throws IllegalStateException
11.763 + * If a decoding operation is already in progress
11.764 + *
11.765 + * @throws MalformedInputException
11.766 + * If the byte sequence starting at the input buffer's current
11.767 + * position is not legal for this charset and the current malformed-input action
11.768 + * is {@link CodingErrorAction#REPORT}
11.769 + *
11.770 + * @throws UnmappableCharacterException
11.771 + * If the byte sequence starting at the input buffer's current
11.772 + * position cannot be mapped to an equivalent character sequence and
11.773 + * the current unmappable-character action is {@link
11.774 + * CodingErrorAction#REPORT}
11.775 + */
11.776 + public final CharBuffer decode(ByteBuffer in)
11.777 + throws CharacterCodingException
11.778 + {
11.779 + int n = (int)(in.remaining() * averageCharsPerByte());
11.780 + CharBuffer out = CharBuffer.allocate(n);
11.781 +
11.782 + if ((n == 0) && (in.remaining() == 0))
11.783 + return out;
11.784 + reset();
11.785 + for (;;) {
11.786 + CoderResult cr = in.hasRemaining() ?
11.787 + decode(in, out, true) : CoderResult.UNDERFLOW;
11.788 + if (cr.isUnderflow())
11.789 + cr = flush(out);
11.790 +
11.791 + if (cr.isUnderflow())
11.792 + break;
11.793 + if (cr.isOverflow()) {
11.794 + n = 2*n + 1; // Ensure progress; n might be 0!
11.795 + CharBuffer o = CharBuffer.allocate(n);
11.796 + out.flip();
11.797 + o.put(out);
11.798 + out = o;
11.799 + continue;
11.800 + }
11.801 + cr.throwException();
11.802 + }
11.803 + out.flip();
11.804 + return out;
11.805 + }
11.806 +
11.807 +
11.808 +
11.809 + /**
11.810 + * Tells whether or not this decoder implements an auto-detecting charset.
11.811 + *
11.812 + * <p> The default implementation of this method always returns
11.813 + * <tt>false</tt>; it should be overridden by auto-detecting decoders to
11.814 + * return <tt>true</tt>. </p>
11.815 + *
11.816 + * @return <tt>true</tt> if, and only if, this decoder implements an
11.817 + * auto-detecting charset
11.818 + */
11.819 + public boolean isAutoDetecting() {
11.820 + return false;
11.821 + }
11.822 +
11.823 + /**
11.824 + * Tells whether or not this decoder has yet detected a
11.825 + * charset <i>(optional operation)</i>.
11.826 + *
11.827 + * <p> If this decoder implements an auto-detecting charset then at a
11.828 + * single point during a decoding operation this method may start returning
11.829 + * <tt>true</tt> to indicate that a specific charset has been detected in
11.830 + * the input byte sequence. Once this occurs, the {@link #detectedCharset
11.831 + * detectedCharset} method may be invoked to retrieve the detected charset.
11.832 + *
11.833 + * <p> That this method returns <tt>false</tt> does not imply that no bytes
11.834 + * have yet been decoded. Some auto-detecting decoders are capable of
11.835 + * decoding some, or even all, of an input byte sequence without fixing on
11.836 + * a particular charset.
11.837 + *
11.838 + * <p> The default implementation of this method always throws an {@link
11.839 + * UnsupportedOperationException}; it should be overridden by
11.840 + * auto-detecting decoders to return <tt>true</tt> once the input charset
11.841 + * has been determined. </p>
11.842 + *
11.843 + * @return <tt>true</tt> if, and only if, this decoder has detected a
11.844 + * specific charset
11.845 + *
11.846 + * @throws UnsupportedOperationException
11.847 + * If this decoder does not implement an auto-detecting charset
11.848 + */
11.849 + public boolean isCharsetDetected() {
11.850 + throw new UnsupportedOperationException();
11.851 + }
11.852 +
11.853 + /**
11.854 + * Retrieves the charset that was detected by this
11.855 + * decoder <i>(optional operation)</i>.
11.856 + *
11.857 + * <p> If this decoder implements an auto-detecting charset then this
11.858 + * method returns the actual charset once it has been detected. After that
11.859 + * point, this method returns the same value for the duration of the
11.860 + * current decoding operation. If not enough input bytes have yet been
11.861 + * read to determine the actual charset then this method throws an {@link
11.862 + * IllegalStateException}.
11.863 + *
11.864 + * <p> The default implementation of this method always throws an {@link
11.865 + * UnsupportedOperationException}; it should be overridden by
11.866 + * auto-detecting decoders to return the appropriate value. </p>
11.867 + *
11.868 + * @return The charset detected by this auto-detecting decoder,
11.869 + * or <tt>null</tt> if the charset has not yet been determined
11.870 + *
11.871 + * @throws IllegalStateException
11.872 + * If insufficient bytes have been read to determine a charset
11.873 + *
11.874 + * @throws UnsupportedOperationException
11.875 + * If this decoder does not implement an auto-detecting charset
11.876 + */
11.877 + public Charset detectedCharset() {
11.878 + throw new UnsupportedOperationException();
11.879 + }
11.880 +
11.881 +
11.882 +
11.883 +
11.884 +
11.885 +
11.886 +
11.887 +
11.888 +
11.889 +
11.890 +
11.891 +
11.892 +
11.893 +
11.894 +
11.895 +
11.896 +
11.897 +
11.898 +
11.899 +
11.900 +
11.901 +
11.902 +
11.903 +
11.904 +
11.905 +
11.906 +
11.907 +
11.908 +
11.909 +
11.910 +
11.911 +
11.912 +
11.913 +
11.914 +
11.915 +
11.916 +
11.917 +
11.918 +
11.919 +
11.920 +
11.921 +
11.922 +
11.923 +
11.924 +
11.925 +
11.926 +
11.927 +
11.928 +
11.929 +
11.930 +
11.931 +
11.932 +
11.933 +
11.934 +
11.935 +
11.936 +
11.937 +
11.938 +
11.939 +
11.940 +
11.941 +
11.942 +
11.943 +
11.944 +
11.945 +
11.946 +
11.947 +
11.948 +
11.949 +
11.950 +
11.951 +
11.952 +
11.953 +
11.954 +
11.955 +
11.956 +
11.957 +
11.958 +
11.959 +
11.960 +
11.961 +
11.962 +
11.963 +
11.964 +
11.965 +
11.966 +
11.967 +
11.968 +
11.969 +
11.970 + private void throwIllegalStateException(int from, int to) {
11.971 + throw new IllegalStateException("Current state = " + stateNames[from]
11.972 + + ", new state = " + stateNames[to]);
11.973 + }
11.974 +
11.975 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetEncoder.java Thu Oct 03 15:40:35 2013 +0200
12.3 @@ -0,0 +1,972 @@
12.4 +/*
12.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
12.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
12.7 + *
12.8 + *
12.9 + *
12.10 + *
12.11 + *
12.12 + *
12.13 + *
12.14 + *
12.15 + *
12.16 + *
12.17 + *
12.18 + *
12.19 + *
12.20 + *
12.21 + *
12.22 + *
12.23 + *
12.24 + *
12.25 + *
12.26 + *
12.27 + */
12.28 +
12.29 +// -- This file was mechanically generated: Do not edit! -- //
12.30 +
12.31 +package java.nio.charset;
12.32 +
12.33 +import java.nio.Buffer;
12.34 +import java.nio.ByteBuffer;
12.35 +import java.nio.CharBuffer;
12.36 +import java.nio.BufferOverflowException;
12.37 +import java.nio.BufferUnderflowException;
12.38 +import java.lang.ref.WeakReference;
12.39 +import java.nio.charset.CoderMalfunctionError; // javadoc
12.40 +
12.41 +
12.42 +/**
12.43 + * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
12.44 + * bytes in a specific charset.
12.45 + *
12.46 + * <a name="steps">
12.47 + *
12.48 + * <p> The input character sequence is provided in a character buffer or a series
12.49 + * of such buffers. The output byte sequence is written to a byte buffer
12.50 + * or a series of such buffers. An encoder should always be used by making
12.51 + * the following sequence of method invocations, hereinafter referred to as an
12.52 + * <i>encoding operation</i>:
12.53 + *
12.54 + * <ol>
12.55 + *
12.56 + * <li><p> Reset the encoder via the {@link #reset reset} method, unless it
12.57 + * has not been used before; </p></li>
12.58 + *
12.59 + * <li><p> Invoke the {@link #encode encode} method zero or more times, as
12.60 + * long as additional input may be available, passing <tt>false</tt> for the
12.61 + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
12.62 + * output buffer between invocations; </p></li>
12.63 + *
12.64 + * <li><p> Invoke the {@link #encode encode} method one final time, passing
12.65 + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
12.66 + *
12.67 + * <li><p> Invoke the {@link #flush flush} method so that the encoder can
12.68 + * flush any internal state to the output buffer. </p></li>
12.69 + *
12.70 + * </ol>
12.71 + *
12.72 + * Each invocation of the {@link #encode encode} method will encode as many
12.73 + * characters as possible from the input buffer, writing the resulting bytes
12.74 + * to the output buffer. The {@link #encode encode} method returns when more
12.75 + * input is required, when there is not enough room in the output buffer, or
12.76 + * when an encoding error has occurred. In each case a {@link CoderResult}
12.77 + * object is returned to describe the reason for termination. An invoker can
12.78 + * examine this object and fill the input buffer, flush the output buffer, or
12.79 + * attempt to recover from an encoding error, as appropriate, and try again.
12.80 + *
12.81 + * <a name="ce">
12.82 + *
12.83 + * <p> There are two general types of encoding errors. If the input character
12.84 + * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>. If
12.85 + * the input character sequence is legal but cannot be mapped to a valid
12.86 + * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
12.87 + *
12.88 + * <a name="cae">
12.89 + *
12.90 + * <p> How an encoding error is handled depends upon the action requested for
12.91 + * that type of error, which is described by an instance of the {@link
12.92 + * CodingErrorAction} class. The possible error actions are to {@link
12.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
12.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
12.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
12.96 + * </code>replace<code>} the erroneous input with the current value of the
12.97 + * replacement byte array. The replacement
12.98 + *
12.99 +
12.100 + * is initially set to the encoder's default replacement, which often
12.101 + * (but not always) has the initial value <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>;
12.102 +
12.103 +
12.104 +
12.105 +
12.106 + *
12.107 + * its value may be changed via the {@link #replaceWith(byte[])
12.108 + * replaceWith} method.
12.109 + *
12.110 + * <p> The default action for malformed-input and unmappable-character errors
12.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
12.112 + * malformed-input error action may be changed via the {@link
12.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
12.114 + * unmappable-character action may be changed via the {@link
12.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
12.116 + *
12.117 + * <p> This class is designed to handle many of the details of the encoding
12.118 + * process, including the implementation of error actions. An encoder for a
12.119 + * specific charset, which is a concrete subclass of this class, need only
12.120 + * implement the abstract {@link #encodeLoop encodeLoop} method, which
12.121 + * encapsulates the basic encoding loop. A subclass that maintains internal
12.122 + * state should, additionally, override the {@link #implFlush implFlush} and
12.123 + * {@link #implReset implReset} methods.
12.124 + *
12.125 + * <p> Instances of this class are not safe for use by multiple concurrent
12.126 + * threads. </p>
12.127 + *
12.128 + *
12.129 + * @author Mark Reinhold
12.130 + * @author JSR-51 Expert Group
12.131 + * @since 1.4
12.132 + *
12.133 + * @see ByteBuffer
12.134 + * @see CharBuffer
12.135 + * @see Charset
12.136 + * @see CharsetDecoder
12.137 + */
12.138 +
12.139 +public abstract class CharsetEncoder {
12.140 +
12.141 + private final Charset charset;
12.142 + private final float averageBytesPerChar;
12.143 + private final float maxBytesPerChar;
12.144 +
12.145 + private byte[] replacement;
12.146 + private CodingErrorAction malformedInputAction
12.147 + = CodingErrorAction.REPORT;
12.148 + private CodingErrorAction unmappableCharacterAction
12.149 + = CodingErrorAction.REPORT;
12.150 +
12.151 + // Internal states
12.152 + //
12.153 + private static final int ST_RESET = 0;
12.154 + private static final int ST_CODING = 1;
12.155 + private static final int ST_END = 2;
12.156 + private static final int ST_FLUSHED = 3;
12.157 +
12.158 + private int state = ST_RESET;
12.159 +
12.160 + private static String stateNames[]
12.161 + = { "RESET", "CODING", "CODING_END", "FLUSHED" };
12.162 +
12.163 +
12.164 + /**
12.165 + * Initializes a new encoder. The new encoder will have the given
12.166 + * bytes-per-char and replacement values. </p>
12.167 + *
12.168 + * @param averageBytesPerChar
12.169 + * A positive float value indicating the expected number of
12.170 + * bytes that will be produced for each input character
12.171 + *
12.172 + * @param maxBytesPerChar
12.173 + * A positive float value indicating the maximum number of
12.174 + * bytes that will be produced for each input character
12.175 + *
12.176 + * @param replacement
12.177 + * The initial replacement; must not be <tt>null</tt>, must have
12.178 + * non-zero length, must not be longer than maxBytesPerChar,
12.179 + * and must be {@link #isLegalReplacement </code>legal<code>}
12.180 + *
12.181 + * @throws IllegalArgumentException
12.182 + * If the preconditions on the parameters do not hold
12.183 + */
12.184 + protected
12.185 + CharsetEncoder(Charset cs,
12.186 + float averageBytesPerChar,
12.187 + float maxBytesPerChar,
12.188 + byte[] replacement)
12.189 + {
12.190 + this.charset = cs;
12.191 + if (averageBytesPerChar <= 0.0f)
12.192 + throw new IllegalArgumentException("Non-positive "
12.193 + + "averageBytesPerChar");
12.194 + if (maxBytesPerChar <= 0.0f)
12.195 + throw new IllegalArgumentException("Non-positive "
12.196 + + "maxBytesPerChar");
12.197 + if (!Charset.atBugLevel("1.4")) {
12.198 + if (averageBytesPerChar > maxBytesPerChar)
12.199 + throw new IllegalArgumentException("averageBytesPerChar"
12.200 + + " exceeds "
12.201 + + "maxBytesPerChar");
12.202 + }
12.203 + this.replacement = replacement;
12.204 + this.averageBytesPerChar = averageBytesPerChar;
12.205 + this.maxBytesPerChar = maxBytesPerChar;
12.206 + replaceWith(replacement);
12.207 + }
12.208 +
12.209 + /**
12.210 + * Initializes a new encoder. The new encoder will have the given
12.211 + * bytes-per-char values and its replacement will be the
12.212 + * byte array <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>. </p>
12.213 + *
12.214 + * @param averageBytesPerChar
12.215 + * A positive float value indicating the expected number of
12.216 + * bytes that will be produced for each input character
12.217 + *
12.218 + * @param maxBytesPerChar
12.219 + * A positive float value indicating the maximum number of
12.220 + * bytes that will be produced for each input character
12.221 + *
12.222 + * @throws IllegalArgumentException
12.223 + * If the preconditions on the parameters do not hold
12.224 + */
12.225 + protected CharsetEncoder(Charset cs,
12.226 + float averageBytesPerChar,
12.227 + float maxBytesPerChar)
12.228 + {
12.229 + this(cs,
12.230 + averageBytesPerChar, maxBytesPerChar,
12.231 + new byte[] { (byte)'?' });
12.232 + }
12.233 +
12.234 + /**
12.235 + * Returns the charset that created this encoder. </p>
12.236 + *
12.237 + * @return This encoder's charset
12.238 + */
12.239 + public final Charset charset() {
12.240 + return charset;
12.241 + }
12.242 +
12.243 + /**
12.244 + * Returns this encoder's replacement value. </p>
12.245 + *
12.246 + * @return This encoder's current replacement,
12.247 + * which is never <tt>null</tt> and is never empty
12.248 + */
12.249 + public final byte[] replacement() {
12.250 + return replacement;
12.251 + }
12.252 +
12.253 + /**
12.254 + * Changes this encoder's replacement value.
12.255 + *
12.256 + * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
12.257 + * method, passing the new replacement, after checking that the new
12.258 + * replacement is acceptable. </p>
12.259 + *
12.260 + * @param newReplacement
12.261 + *
12.262 +
12.263 +
12.264 +
12.265 +
12.266 +
12.267 + * The new replacement; must not be <tt>null</tt>, must have
12.268 + * non-zero length, must not be longer than the value returned by
12.269 + * the {@link #maxBytesPerChar() maxBytesPerChar} method, and
12.270 + * must be {@link #isLegalReplacement </code>legal<code>}
12.271 +
12.272 + *
12.273 + * @return This encoder
12.274 + *
12.275 + * @throws IllegalArgumentException
12.276 + * If the preconditions on the parameter do not hold
12.277 + */
12.278 + public final CharsetEncoder replaceWith(byte[] newReplacement) {
12.279 + if (newReplacement == null)
12.280 + throw new IllegalArgumentException("Null replacement");
12.281 + int len = newReplacement.length;
12.282 + if (len == 0)
12.283 + throw new IllegalArgumentException("Empty replacement");
12.284 + if (len > maxBytesPerChar)
12.285 + throw new IllegalArgumentException("Replacement too long");
12.286 +
12.287 + if (!isLegalReplacement(newReplacement))
12.288 + throw new IllegalArgumentException("Illegal replacement");
12.289 +
12.290 + this.replacement = newReplacement;
12.291 + implReplaceWith(newReplacement);
12.292 + return this;
12.293 + }
12.294 +
12.295 + /**
12.296 + * Reports a change to this encoder's replacement value.
12.297 + *
12.298 + * <p> The default implementation of this method does nothing. This method
12.299 + * should be overridden by encoders that require notification of changes to
12.300 + * the replacement. </p>
12.301 + *
12.302 + * @param newReplacement
12.303 + */
12.304 + protected void implReplaceWith(byte[] newReplacement) {
12.305 + }
12.306 +
12.307 +
12.308 +
12.309 + private WeakReference<CharsetDecoder> cachedDecoder = null;
12.310 +
12.311 + /**
12.312 + * Tells whether or not the given byte array is a legal replacement value
12.313 + * for this encoder.
12.314 + *
12.315 + * <p> A replacement is legal if, and only if, it is a legal sequence of
12.316 + * bytes in this encoder's charset; that is, it must be possible to decode
12.317 + * the replacement into one or more sixteen-bit Unicode characters.
12.318 + *
12.319 + * <p> The default implementation of this method is not very efficient; it
12.320 + * should generally be overridden to improve performance. </p>
12.321 + *
12.322 + * @param repl The byte array to be tested
12.323 + *
12.324 + * @return <tt>true</tt> if, and only if, the given byte array
12.325 + * is a legal replacement value for this encoder
12.326 + */
12.327 + public boolean isLegalReplacement(byte[] repl) {
12.328 + WeakReference<CharsetDecoder> wr = cachedDecoder;
12.329 + CharsetDecoder dec = null;
12.330 + if ((wr == null) || ((dec = wr.get()) == null)) {
12.331 + dec = charset().newDecoder();
12.332 + dec.onMalformedInput(CodingErrorAction.REPORT);
12.333 + dec.onUnmappableCharacter(CodingErrorAction.REPORT);
12.334 + cachedDecoder = new WeakReference<CharsetDecoder>(dec);
12.335 + } else {
12.336 + dec.reset();
12.337 + }
12.338 + ByteBuffer bb = ByteBuffer.wrap(repl);
12.339 + CharBuffer cb = CharBuffer.allocate((int)(bb.remaining()
12.340 + * dec.maxCharsPerByte()));
12.341 + CoderResult cr = dec.decode(bb, cb, true);
12.342 + return !cr.isError();
12.343 + }
12.344 +
12.345 +
12.346 +
12.347 + /**
12.348 + * Returns this encoder's current action for malformed-input errors. </p>
12.349 + *
12.350 + * @return The current malformed-input action, which is never <tt>null</tt>
12.351 + */
12.352 + public CodingErrorAction malformedInputAction() {
12.353 + return malformedInputAction;
12.354 + }
12.355 +
12.356 + /**
12.357 + * Changes this encoder's action for malformed-input errors. </p>
12.358 + *
12.359 + * <p> This method invokes the {@link #implOnMalformedInput
12.360 + * implOnMalformedInput} method, passing the new action. </p>
12.361 + *
12.362 + * @param newAction The new action; must not be <tt>null</tt>
12.363 + *
12.364 + * @return This encoder
12.365 + *
12.366 + * @throws IllegalArgumentException
12.367 + * If the precondition on the parameter does not hold
12.368 + */
12.369 + public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
12.370 + if (newAction == null)
12.371 + throw new IllegalArgumentException("Null action");
12.372 + malformedInputAction = newAction;
12.373 + implOnMalformedInput(newAction);
12.374 + return this;
12.375 + }
12.376 +
12.377 + /**
12.378 + * Reports a change to this encoder's malformed-input action.
12.379 + *
12.380 + * <p> The default implementation of this method does nothing. This method
12.381 + * should be overridden by encoders that require notification of changes to
12.382 + * the malformed-input action. </p>
12.383 + */
12.384 + protected void implOnMalformedInput(CodingErrorAction newAction) { }
12.385 +
12.386 + /**
12.387 + * Returns this encoder's current action for unmappable-character errors.
12.388 + * </p>
12.389 + *
12.390 + * @return The current unmappable-character action, which is never
12.391 + * <tt>null</tt>
12.392 + */
12.393 + public CodingErrorAction unmappableCharacterAction() {
12.394 + return unmappableCharacterAction;
12.395 + }
12.396 +
12.397 + /**
12.398 + * Changes this encoder's action for unmappable-character errors.
12.399 + *
12.400 + * <p> This method invokes the {@link #implOnUnmappableCharacter
12.401 + * implOnUnmappableCharacter} method, passing the new action. </p>
12.402 + *
12.403 + * @param newAction The new action; must not be <tt>null</tt>
12.404 + *
12.405 + * @return This encoder
12.406 + *
12.407 + * @throws IllegalArgumentException
12.408 + * If the precondition on the parameter does not hold
12.409 + */
12.410 + public final CharsetEncoder onUnmappableCharacter(CodingErrorAction
12.411 + newAction)
12.412 + {
12.413 + if (newAction == null)
12.414 + throw new IllegalArgumentException("Null action");
12.415 + unmappableCharacterAction = newAction;
12.416 + implOnUnmappableCharacter(newAction);
12.417 + return this;
12.418 + }
12.419 +
12.420 + /**
12.421 + * Reports a change to this encoder's unmappable-character action.
12.422 + *
12.423 + * <p> The default implementation of this method does nothing. This method
12.424 + * should be overridden by encoders that require notification of changes to
12.425 + * the unmappable-character action. </p>
12.426 + */
12.427 + protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
12.428 +
12.429 + /**
12.430 + * Returns the average number of bytes that will be produced for each
12.431 + * character of input. This heuristic value may be used to estimate the size
12.432 + * of the output buffer required for a given input sequence. </p>
12.433 + *
12.434 + * @return The average number of bytes produced
12.435 + * per character of input
12.436 + */
12.437 + public final float averageBytesPerChar() {
12.438 + return averageBytesPerChar;
12.439 + }
12.440 +
12.441 + /**
12.442 + * Returns the maximum number of bytes that will be produced for each
12.443 + * character of input. This value may be used to compute the worst-case size
12.444 + * of the output buffer required for a given input sequence. </p>
12.445 + *
12.446 + * @return The maximum number of bytes that will be produced per
12.447 + * character of input
12.448 + */
12.449 + public final float maxBytesPerChar() {
12.450 + return maxBytesPerChar;
12.451 + }
12.452 +
12.453 + /**
12.454 + * Encodes as many characters as possible from the given input buffer,
12.455 + * writing the results to the given output buffer.
12.456 + *
12.457 + * <p> The buffers are read from, and written to, starting at their current
12.458 + * positions. At most {@link Buffer#remaining in.remaining()} characters
12.459 + * will be read and at most {@link Buffer#remaining out.remaining()}
12.460 + * bytes will be written. The buffers' positions will be advanced to
12.461 + * reflect the characters read and the bytes written, but their marks and
12.462 + * limits will not be modified.
12.463 + *
12.464 + * <p> In addition to reading characters from the input buffer and writing
12.465 + * bytes to the output buffer, this method returns a {@link CoderResult}
12.466 + * object to describe its reason for termination:
12.467 + *
12.468 + * <ul>
12.469 + *
12.470 + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
12.471 + * input buffer as possible has been encoded. If there is no further
12.472 + * input then the invoker can proceed to the next step of the
12.473 + * <a href="#steps">encoding operation</a>. Otherwise this method
12.474 + * should be invoked again with further input. </p></li>
12.475 + *
12.476 + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is
12.477 + * insufficient space in the output buffer to encode any more characters.
12.478 + * This method should be invoked again with an output buffer that has
12.479 + * more {@linkplain Buffer#remaining remaining} bytes. This is
12.480 + * typically done by draining any encoded bytes from the output
12.481 + * buffer. </p></li>
12.482 + *
12.483 + * <li><p> A {@link CoderResult#malformedForLength
12.484 + * </code>malformed-input<code>} result indicates that a malformed-input
12.485 + * error has been detected. The malformed characters begin at the input
12.486 + * buffer's (possibly incremented) position; the number of malformed
12.487 + * characters may be determined by invoking the result object's {@link
12.488 + * CoderResult#length() length} method. This case applies only if the
12.489 + * {@link #onMalformedInput </code>malformed action<code>} of this encoder
12.490 + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
12.491 + * will be ignored or replaced, as requested. </p></li>
12.492 + *
12.493 + * <li><p> An {@link CoderResult#unmappableForLength
12.494 + * </code>unmappable-character<code>} result indicates that an
12.495 + * unmappable-character error has been detected. The characters that
12.496 + * encode the unmappable character begin at the input buffer's (possibly
12.497 + * incremented) position; the number of such characters may be determined
12.498 + * by invoking the result object's {@link CoderResult#length() length}
12.499 + * method. This case applies only if the {@link #onUnmappableCharacter
12.500 + * </code>unmappable action<code>} of this encoder is {@link
12.501 + * CodingErrorAction#REPORT}; otherwise the unmappable character will be
12.502 + * ignored or replaced, as requested. </p></li>
12.503 + *
12.504 + * </ul>
12.505 + *
12.506 + * In any case, if this method is to be reinvoked in the same encoding
12.507 + * operation then care should be taken to preserve any characters remaining
12.508 + * in the input buffer so that they are available to the next invocation.
12.509 + *
12.510 + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
12.511 + * the invoker can provide further input beyond that contained in the given
12.512 + * input buffer. If there is a possibility of providing additional input
12.513 + * then the invoker should pass <tt>false</tt> for this parameter; if there
12.514 + * is no possibility of providing further input then the invoker should
12.515 + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
12.516 + * common, to pass <tt>false</tt> in one invocation and later discover that
12.517 + * no further input was actually available. It is critical, however, that
12.518 + * the final invocation of this method in a sequence of invocations always
12.519 + * pass <tt>true</tt> so that any remaining unencoded input will be treated
12.520 + * as being malformed.
12.521 + *
12.522 + * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
12.523 + * method, interpreting its results, handling error conditions, and
12.524 + * reinvoking it as necessary. </p>
12.525 + *
12.526 + *
12.527 + * @param in
12.528 + * The input character buffer
12.529 + *
12.530 + * @param out
12.531 + * The output byte buffer
12.532 + *
12.533 + * @param endOfInput
12.534 + * <tt>true</tt> if, and only if, the invoker can provide no
12.535 + * additional input characters beyond those in the given buffer
12.536 + *
12.537 + * @return A coder-result object describing the reason for termination
12.538 + *
12.539 + * @throws IllegalStateException
12.540 + * If an encoding operation is already in progress and the previous
12.541 + * step was an invocation neither of the {@link #reset reset}
12.542 + * method, nor of this method with a value of <tt>false</tt> for
12.543 + * the <tt>endOfInput</tt> parameter, nor of this method with a
12.544 + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
12.545 + * but a return value indicating an incomplete encoding operation
12.546 + *
12.547 + * @throws CoderMalfunctionError
12.548 + * If an invocation of the encodeLoop method threw
12.549 + * an unexpected exception
12.550 + */
12.551 + public final CoderResult encode(CharBuffer in, ByteBuffer out,
12.552 + boolean endOfInput)
12.553 + {
12.554 + int newState = endOfInput ? ST_END : ST_CODING;
12.555 + if ((state != ST_RESET) && (state != ST_CODING)
12.556 + && !(endOfInput && (state == ST_END)))
12.557 + throwIllegalStateException(state, newState);
12.558 + state = newState;
12.559 +
12.560 + for (;;) {
12.561 +
12.562 + CoderResult cr;
12.563 + try {
12.564 + cr = encodeLoop(in, out);
12.565 + } catch (BufferUnderflowException x) {
12.566 + throw new CoderMalfunctionError(x);
12.567 + } catch (BufferOverflowException x) {
12.568 + throw new CoderMalfunctionError(x);
12.569 + }
12.570 +
12.571 + if (cr.isOverflow())
12.572 + return cr;
12.573 +
12.574 + if (cr.isUnderflow()) {
12.575 + if (endOfInput && in.hasRemaining()) {
12.576 + cr = CoderResult.malformedForLength(in.remaining());
12.577 + // Fall through to malformed-input case
12.578 + } else {
12.579 + return cr;
12.580 + }
12.581 + }
12.582 +
12.583 + CodingErrorAction action = null;
12.584 + if (cr.isMalformed())
12.585 + action = malformedInputAction;
12.586 + else if (cr.isUnmappable())
12.587 + action = unmappableCharacterAction;
12.588 + else
12.589 + assert false : cr.toString();
12.590 +
12.591 + if (action == CodingErrorAction.REPORT)
12.592 + return cr;
12.593 +
12.594 + if (action == CodingErrorAction.REPLACE) {
12.595 + if (out.remaining() < replacement.length)
12.596 + return CoderResult.OVERFLOW;
12.597 + out.put(replacement);
12.598 + }
12.599 +
12.600 + if ((action == CodingErrorAction.IGNORE)
12.601 + || (action == CodingErrorAction.REPLACE)) {
12.602 + // Skip erroneous input either way
12.603 + in.position(in.position() + cr.length());
12.604 + continue;
12.605 + }
12.606 +
12.607 + assert false;
12.608 + }
12.609 +
12.610 + }
12.611 +
12.612 + /**
12.613 + * Flushes this encoder.
12.614 + *
12.615 + * <p> Some encoders maintain internal state and may need to write some
12.616 + * final bytes to the output buffer once the overall input sequence has
12.617 + * been read.
12.618 + *
12.619 + * <p> Any additional output is written to the output buffer beginning at
12.620 + * its current position. At most {@link Buffer#remaining out.remaining()}
12.621 + * bytes will be written. The buffer's position will be advanced
12.622 + * appropriately, but its mark and limit will not be modified.
12.623 + *
12.624 + * <p> If this method completes successfully then it returns {@link
12.625 + * CoderResult#UNDERFLOW}. If there is insufficient room in the output
12.626 + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
12.627 + * then this method must be invoked again, with an output buffer that has
12.628 + * more room, in order to complete the current <a href="#steps">encoding
12.629 + * operation</a>.
12.630 + *
12.631 + * <p> If this encoder has already been flushed then invoking this method
12.632 + * has no effect.
12.633 + *
12.634 + * <p> This method invokes the {@link #implFlush implFlush} method to
12.635 + * perform the actual flushing operation. </p>
12.636 + *
12.637 + * @param out
12.638 + * The output byte buffer
12.639 + *
12.640 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
12.641 + * {@link CoderResult#OVERFLOW}
12.642 + *
12.643 + * @throws IllegalStateException
12.644 + * If the previous step of the current encoding operation was an
12.645 + * invocation neither of the {@link #flush flush} method nor of
12.646 + * the three-argument {@link
12.647 + * #encode(CharBuffer,ByteBuffer,boolean) encode} method
12.648 + * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
12.649 + * parameter
12.650 + */
12.651 + public final CoderResult flush(ByteBuffer out) {
12.652 + if (state == ST_END) {
12.653 + CoderResult cr = implFlush(out);
12.654 + if (cr.isUnderflow())
12.655 + state = ST_FLUSHED;
12.656 + return cr;
12.657 + }
12.658 +
12.659 + if (state != ST_FLUSHED)
12.660 + throwIllegalStateException(state, ST_FLUSHED);
12.661 +
12.662 + return CoderResult.UNDERFLOW; // Already flushed
12.663 + }
12.664 +
12.665 + /**
12.666 + * Flushes this encoder.
12.667 + *
12.668 + * <p> The default implementation of this method does nothing, and always
12.669 + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
12.670 + * by encoders that may need to write final bytes to the output buffer
12.671 + * once the entire input sequence has been read. </p>
12.672 + *
12.673 + * @param out
12.674 + * The output byte buffer
12.675 + *
12.676 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
12.677 + * {@link CoderResult#OVERFLOW}
12.678 + */
12.679 + protected CoderResult implFlush(ByteBuffer out) {
12.680 + return CoderResult.UNDERFLOW;
12.681 + }
12.682 +
12.683 + /**
12.684 + * Resets this encoder, clearing any internal state.
12.685 + *
12.686 + * <p> This method resets charset-independent state and also invokes the
12.687 + * {@link #implReset() implReset} method in order to perform any
12.688 + * charset-specific reset actions. </p>
12.689 + *
12.690 + * @return This encoder
12.691 + *
12.692 + */
12.693 + public final CharsetEncoder reset() {
12.694 + implReset();
12.695 + state = ST_RESET;
12.696 + return this;
12.697 + }
12.698 +
12.699 + /**
12.700 + * Resets this encoder, clearing any charset-specific internal state.
12.701 + *
12.702 + * <p> The default implementation of this method does nothing. This method
12.703 + * should be overridden by encoders that maintain internal state. </p>
12.704 + */
12.705 + protected void implReset() { }
12.706 +
12.707 + /**
12.708 + * Encodes one or more characters into one or more bytes.
12.709 + *
12.710 + * <p> This method encapsulates the basic encoding loop, encoding as many
12.711 + * characters as possible until it either runs out of input, runs out of room
12.712 + * in the output buffer, or encounters an encoding error. This method is
12.713 + * invoked by the {@link #encode encode} method, which handles result
12.714 + * interpretation and error recovery.
12.715 + *
12.716 + * <p> The buffers are read from, and written to, starting at their current
12.717 + * positions. At most {@link Buffer#remaining in.remaining()} characters
12.718 + * will be read, and at most {@link Buffer#remaining out.remaining()}
12.719 + * bytes will be written. The buffers' positions will be advanced to
12.720 + * reflect the characters read and the bytes written, but their marks and
12.721 + * limits will not be modified.
12.722 + *
12.723 + * <p> This method returns a {@link CoderResult} object to describe its
12.724 + * reason for termination, in the same manner as the {@link #encode encode}
12.725 + * method. Most implementations of this method will handle encoding errors
12.726 + * by returning an appropriate result object for interpretation by the
12.727 + * {@link #encode encode} method. An optimized implementation may instead
12.728 + * examine the relevant error action and implement that action itself.
12.729 + *
12.730 + * <p> An implementation of this method may perform arbitrary lookahead by
12.731 + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
12.732 + * input. </p>
12.733 + *
12.734 + * @param in
12.735 + * The input character buffer
12.736 + *
12.737 + * @param out
12.738 + * The output byte buffer
12.739 + *
12.740 + * @return A coder-result object describing the reason for termination
12.741 + */
12.742 + protected abstract CoderResult encodeLoop(CharBuffer in,
12.743 + ByteBuffer out);
12.744 +
12.745 + /**
12.746 + * Convenience method that encodes the remaining content of a single input
12.747 + * character buffer into a newly-allocated byte buffer.
12.748 + *
12.749 + * <p> This method implements an entire <a href="#steps">encoding
12.750 + * operation</a>; that is, it resets this encoder, then it encodes the
12.751 + * characters in the given character buffer, and finally it flushes this
12.752 + * encoder. This method should therefore not be invoked if an encoding
12.753 + * operation is already in progress. </p>
12.754 + *
12.755 + * @param in
12.756 + * The input character buffer
12.757 + *
12.758 + * @return A newly-allocated byte buffer containing the result of the
12.759 + * encoding operation. The buffer's position will be zero and its
12.760 + * limit will follow the last byte written.
12.761 + *
12.762 + * @throws IllegalStateException
12.763 + * If an encoding operation is already in progress
12.764 + *
12.765 + * @throws MalformedInputException
12.766 + * If the character sequence starting at the input buffer's current
12.767 + * position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
12.768 + * is {@link CodingErrorAction#REPORT}
12.769 + *
12.770 + * @throws UnmappableCharacterException
12.771 + * If the character sequence starting at the input buffer's current
12.772 + * position cannot be mapped to an equivalent byte sequence and
12.773 + * the current unmappable-character action is {@link
12.774 + * CodingErrorAction#REPORT}
12.775 + */
12.776 + public final ByteBuffer encode(CharBuffer in)
12.777 + throws CharacterCodingException
12.778 + {
12.779 + int n = (int)(in.remaining() * averageBytesPerChar());
12.780 + ByteBuffer out = ByteBuffer.allocate(n);
12.781 +
12.782 + if ((n == 0) && (in.remaining() == 0))
12.783 + return out;
12.784 + reset();
12.785 + for (;;) {
12.786 + CoderResult cr = in.hasRemaining() ?
12.787 + encode(in, out, true) : CoderResult.UNDERFLOW;
12.788 + if (cr.isUnderflow())
12.789 + cr = flush(out);
12.790 +
12.791 + if (cr.isUnderflow())
12.792 + break;
12.793 + if (cr.isOverflow()) {
12.794 + n = 2*n + 1; // Ensure progress; n might be 0!
12.795 + ByteBuffer o = ByteBuffer.allocate(n);
12.796 + out.flip();
12.797 + o.put(out);
12.798 + out = o;
12.799 + continue;
12.800 + }
12.801 + cr.throwException();
12.802 + }
12.803 + out.flip();
12.804 + return out;
12.805 + }
12.806 +
12.807 +
12.808 +
12.809 +
12.810 +
12.811 +
12.812 +
12.813 +
12.814 +
12.815 +
12.816 +
12.817 +
12.818 +
12.819 +
12.820 +
12.821 +
12.822 +
12.823 +
12.824 +
12.825 +
12.826 +
12.827 +
12.828 +
12.829 +
12.830 +
12.831 +
12.832 +
12.833 +
12.834 +
12.835 +
12.836 +
12.837 +
12.838 +
12.839 +
12.840 +
12.841 +
12.842 +
12.843 +
12.844 +
12.845 +
12.846 +
12.847 +
12.848 +
12.849 +
12.850 +
12.851 +
12.852 +
12.853 +
12.854 +
12.855 +
12.856 +
12.857 +
12.858 +
12.859 +
12.860 +
12.861 +
12.862 +
12.863 +
12.864 +
12.865 +
12.866 +
12.867 +
12.868 +
12.869 +
12.870 +
12.871 +
12.872 +
12.873 +
12.874 +
12.875 +
12.876 +
12.877 +
12.878 +
12.879 +
12.880 +
12.881 +
12.882 +
12.883 +
12.884 +
12.885 + private boolean canEncode(CharBuffer cb) {
12.886 + if (state == ST_FLUSHED)
12.887 + reset();
12.888 + else if (state != ST_RESET)
12.889 + throwIllegalStateException(state, ST_CODING);
12.890 + CodingErrorAction ma = malformedInputAction();
12.891 + CodingErrorAction ua = unmappableCharacterAction();
12.892 + try {
12.893 + onMalformedInput(CodingErrorAction.REPORT);
12.894 + onUnmappableCharacter(CodingErrorAction.REPORT);
12.895 + encode(cb);
12.896 + } catch (CharacterCodingException x) {
12.897 + return false;
12.898 + } finally {
12.899 + onMalformedInput(ma);
12.900 + onUnmappableCharacter(ua);
12.901 + reset();
12.902 + }
12.903 + return true;
12.904 + }
12.905 +
12.906 + /**
12.907 + * Tells whether or not this encoder can encode the given character.
12.908 + *
12.909 + * <p> This method returns <tt>false</tt> if the given character is a
12.910 + * surrogate character; such characters can be interpreted only when they
12.911 + * are members of a pair consisting of a high surrogate followed by a low
12.912 + * surrogate. The {@link #canEncode(java.lang.CharSequence)
12.913 + * canEncode(CharSequence)} method may be used to test whether or not a
12.914 + * character sequence can be encoded.
12.915 + *
12.916 + * <p> This method may modify this encoder's state; it should therefore not
12.917 + * be invoked if an <a href="#steps">encoding operation</a> is already in
12.918 + * progress.
12.919 + *
12.920 + * <p> The default implementation of this method is not very efficient; it
12.921 + * should generally be overridden to improve performance. </p>
12.922 + *
12.923 + * @return <tt>true</tt> if, and only if, this encoder can encode
12.924 + * the given character
12.925 + *
12.926 + * @throws IllegalStateException
12.927 + * If an encoding operation is already in progress
12.928 + */
12.929 + public boolean canEncode(char c) {
12.930 + CharBuffer cb = CharBuffer.allocate(1);
12.931 + cb.put(c);
12.932 + cb.flip();
12.933 + return canEncode(cb);
12.934 + }
12.935 +
12.936 + /**
12.937 + * Tells whether or not this encoder can encode the given character
12.938 + * sequence.
12.939 + *
12.940 + * <p> If this method returns <tt>false</tt> for a particular character
12.941 + * sequence then more information about why the sequence cannot be encoded
12.942 + * may be obtained by performing a full <a href="#steps">encoding
12.943 + * operation</a>.
12.944 + *
12.945 + * <p> This method may modify this encoder's state; it should therefore not
12.946 + * be invoked if an encoding operation is already in progress.
12.947 + *
12.948 + * <p> The default implementation of this method is not very efficient; it
12.949 + * should generally be overridden to improve performance. </p>
12.950 + *
12.951 + * @return <tt>true</tt> if, and only if, this encoder can encode
12.952 + * the given character without throwing any exceptions and without
12.953 + * performing any replacements
12.954 + *
12.955 + * @throws IllegalStateException
12.956 + * If an encoding operation is already in progress
12.957 + */
12.958 + public boolean canEncode(CharSequence cs) {
12.959 + CharBuffer cb;
12.960 + if (cs instanceof CharBuffer)
12.961 + cb = ((CharBuffer)cs).duplicate();
12.962 + else
12.963 + cb = CharBuffer.wrap(cs.toString());
12.964 + return canEncode(cb);
12.965 + }
12.966 +
12.967 +
12.968 +
12.969 +
12.970 + private void throwIllegalStateException(int from, int to) {
12.971 + throw new IllegalStateException("Current state = " + stateNames[from]
12.972 + + ", new state = " + stateNames[to]);
12.973 + }
12.974 +
12.975 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/IllegalCharsetNameException.java Thu Oct 03 15:40:35 2013 +0200
13.3 @@ -0,0 +1,68 @@
13.4 +/*
13.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
13.6 + *
13.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
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 + */
13.30 +
13.31 +// -- This file was mechanically generated: Do not edit! -- //
13.32 +
13.33 +package java.nio.charset;
13.34 +
13.35 +
13.36 +/**
13.37 + * Unchecked exception thrown when a string that is not a
13.38 + * <a href=Charset.html#names>legal charset name</a> is used as such.
13.39 + *
13.40 + * @since 1.4
13.41 + */
13.42 +
13.43 +public class IllegalCharsetNameException
13.44 + extends IllegalArgumentException
13.45 +{
13.46 +
13.47 + private static final long serialVersionUID = 1457525358470002989L;
13.48 +
13.49 + private String charsetName;
13.50 +
13.51 + /**
13.52 + * Constructs an instance of this class. </p>
13.53 + *
13.54 + * @param charsetName
13.55 + * The illegal charset name
13.56 + */
13.57 + public IllegalCharsetNameException(String charsetName) {
13.58 + super(String.valueOf(charsetName));
13.59 + this.charsetName = charsetName;
13.60 + }
13.61 +
13.62 + /**
13.63 + * Retrieves the illegal charset name. </p>
13.64 + *
13.65 + * @return The illegal charset name
13.66 + */
13.67 + public String getCharsetName() {
13.68 + return charsetName;
13.69 + }
13.70 +
13.71 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/UnsupportedCharsetException.java Thu Oct 03 15:40:35 2013 +0200
14.3 @@ -0,0 +1,68 @@
14.4 +/*
14.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
14.6 + *
14.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
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 + */
14.30 +
14.31 +// -- This file was mechanically generated: Do not edit! -- //
14.32 +
14.33 +package java.nio.charset;
14.34 +
14.35 +
14.36 +/**
14.37 + * Unchecked exception thrown when no support is available
14.38 + * for a requested charset.
14.39 + *
14.40 + * @since 1.4
14.41 + */
14.42 +
14.43 +public class UnsupportedCharsetException
14.44 + extends IllegalArgumentException
14.45 +{
14.46 +
14.47 + private static final long serialVersionUID = 1490765524727386367L;
14.48 +
14.49 + private String charsetName;
14.50 +
14.51 + /**
14.52 + * Constructs an instance of this class. </p>
14.53 + *
14.54 + * @param charsetName
14.55 + * The name of the unsupported charset
14.56 + */
14.57 + public UnsupportedCharsetException(String charsetName) {
14.58 + super(String.valueOf(charsetName));
14.59 + this.charsetName = charsetName;
14.60 + }
14.61 +
14.62 + /**
14.63 + * Retrieves the name of the unsupported charset. </p>
14.64 + *
14.65 + * @return The name of the unsupported charset
14.66 + */
14.67 + public String getCharsetName() {
14.68 + return charsetName;
14.69 + }
14.70 +
14.71 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/rt/emul/compact/src/main/java/java/security/AccessController.java Thu Oct 03 15:40:35 2013 +0200
15.3 @@ -0,0 +1,557 @@
15.4 +/*
15.5 + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
15.7 + *
15.8 + * This code is free software; you can redistribute it and/or modify it
15.9 + * under the terms of the GNU General Public License version 2 only, as
15.10 + * published by the Free Software Foundation. Oracle designates this
15.11 + * particular file as subject to the "Classpath" exception as provided
15.12 + * by Oracle in the LICENSE file that accompanied this code.
15.13 + *
15.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
15.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15.17 + * version 2 for more details (a copy is included in the LICENSE file that
15.18 + * accompanied this code).
15.19 + *
15.20 + * You should have received a copy of the GNU General Public License version
15.21 + * 2 along with this work; if not, write to the Free Software Foundation,
15.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
15.23 + *
15.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
15.25 + * or visit www.oracle.com if you need additional information or have any
15.26 + * questions.
15.27 + */
15.28 +
15.29 +package java.security;
15.30 +
15.31 +import sun.security.util.Debug;
15.32 +
15.33 +/**
15.34 + * <p> The AccessController class is used for access control operations
15.35 + * and decisions.
15.36 + *
15.37 + * <p> More specifically, the AccessController class is used for
15.38 + * three purposes:
15.39 + *
15.40 + * <ul>
15.41 + * <li> to decide whether an access to a critical system
15.42 + * resource is to be allowed or denied, based on the security policy
15.43 + * currently in effect,<p>
15.44 + * <li>to mark code as being "privileged", thus affecting subsequent
15.45 + * access determinations, and<p>
15.46 + * <li>to obtain a "snapshot" of the current calling context so
15.47 + * access-control decisions from a different context can be made with
15.48 + * respect to the saved context. </ul>
15.49 + *
15.50 + * <p> The {@link #checkPermission(Permission) checkPermission} method
15.51 + * determines whether the access request indicated by a specified
15.52 + * permission should be granted or denied. A sample call appears
15.53 + * below. In this example, <code>checkPermission</code> will determine
15.54 + * whether or not to grant "read" access to the file named "testFile" in
15.55 + * the "/temp" directory.
15.56 + *
15.57 + * <pre>
15.58 + *
15.59 + * FilePermission perm = new FilePermission("/temp/testFile", "read");
15.60 + * AccessController.checkPermission(perm);
15.61 + *
15.62 + * </pre>
15.63 + *
15.64 + * <p> If a requested access is allowed,
15.65 + * <code>checkPermission</code> returns quietly. If denied, an
15.66 + * AccessControlException is
15.67 + * thrown. AccessControlException can also be thrown if the requested
15.68 + * permission is of an incorrect type or contains an invalid value.
15.69 + * Such information is given whenever possible.
15.70 + *
15.71 + * Suppose the current thread traversed m callers, in the order of caller 1
15.72 + * to caller 2 to caller m. Then caller m invoked the
15.73 + * <code>checkPermission</code> method.
15.74 + * The <code>checkPermission </code>method determines whether access
15.75 + * is granted or denied based on the following algorithm:
15.76 + *
15.77 + * <pre> {@code
15.78 + * for (int i = m; i > 0; i--) {
15.79 + *
15.80 + * if (caller i's domain does not have the permission)
15.81 + * throw AccessControlException
15.82 + *
15.83 + * else if (caller i is marked as privileged) {
15.84 + * if (a context was specified in the call to doPrivileged)
15.85 + * context.checkPermission(permission)
15.86 + * return;
15.87 + * }
15.88 + * };
15.89 + *
15.90 + * // Next, check the context inherited when the thread was created.
15.91 + * // Whenever a new thread is created, the AccessControlContext at
15.92 + * // that time is stored and associated with the new thread, as the
15.93 + * // "inherited" context.
15.94 + *
15.95 + * inheritedContext.checkPermission(permission);
15.96 + * }</pre>
15.97 + *
15.98 + * <p> A caller can be marked as being "privileged"
15.99 + * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
15.100 + * When making access control decisions, the <code>checkPermission</code>
15.101 + * method stops checking if it reaches a caller that
15.102 + * was marked as "privileged" via a <code>doPrivileged</code>
15.103 + * call without a context argument (see below for information about a
15.104 + * context argument). If that caller's domain has the
15.105 + * specified permission, no further checking is done and
15.106 + * <code>checkPermission</code>
15.107 + * returns quietly, indicating that the requested access is allowed.
15.108 + * If that domain does not have the specified permission, an exception
15.109 + * is thrown, as usual.
15.110 + *
15.111 + * <p> The normal use of the "privileged" feature is as follows. If you
15.112 + * don't need to return a value from within the "privileged" block, do
15.113 + * the following:
15.114 + *
15.115 + * <pre> {@code
15.116 + * somemethod() {
15.117 + * ...normal code here...
15.118 + * AccessController.doPrivileged(new PrivilegedAction<Void>() {
15.119 + * public Void run() {
15.120 + * // privileged code goes here, for example:
15.121 + * System.loadLibrary("awt");
15.122 + * return null; // nothing to return
15.123 + * }
15.124 + * });
15.125 + * ...normal code here...
15.126 + * }}</pre>
15.127 + *
15.128 + * <p>
15.129 + * PrivilegedAction is an interface with a single method, named
15.130 + * <code>run</code>.
15.131 + * The above example shows creation of an implementation
15.132 + * of that interface; a concrete implementation of the
15.133 + * <code>run</code> method is supplied.
15.134 + * When the call to <code>doPrivileged</code> is made, an
15.135 + * instance of the PrivilegedAction implementation is passed
15.136 + * to it. The <code>doPrivileged</code> method calls the
15.137 + * <code>run</code> method from the PrivilegedAction
15.138 + * implementation after enabling privileges, and returns the
15.139 + * <code>run</code> method's return value as the
15.140 + * <code>doPrivileged</code> return value (which is
15.141 + * ignored in this example).
15.142 + *
15.143 + * <p> If you need to return a value, you can do something like the following:
15.144 + *
15.145 + * <pre> {@code
15.146 + * somemethod() {
15.147 + * ...normal code here...
15.148 + * String user = AccessController.doPrivileged(
15.149 + * new PrivilegedAction<String>() {
15.150 + * public String run() {
15.151 + * return System.getProperty("user.name");
15.152 + * }
15.153 + * });
15.154 + * ...normal code here...
15.155 + * }}</pre>
15.156 + *
15.157 + * <p>If the action performed in your <code>run</code> method could
15.158 + * throw a "checked" exception (those listed in the <code>throws</code> clause
15.159 + * of a method), then you need to use the
15.160 + * <code>PrivilegedExceptionAction</code> interface instead of the
15.161 + * <code>PrivilegedAction</code> interface:
15.162 + *
15.163 + * <pre> {@code
15.164 + * somemethod() throws FileNotFoundException {
15.165 + * ...normal code here...
15.166 + * try {
15.167 + * FileInputStream fis = AccessController.doPrivileged(
15.168 + * new PrivilegedExceptionAction<FileInputStream>() {
15.169 + * public FileInputStream run() throws FileNotFoundException {
15.170 + * return new FileInputStream("someFile");
15.171 + * }
15.172 + * });
15.173 + * } catch (PrivilegedActionException e) {
15.174 + * // e.getException() should be an instance of FileNotFoundException,
15.175 + * // as only "checked" exceptions will be "wrapped" in a
15.176 + * // PrivilegedActionException.
15.177 + * throw (FileNotFoundException) e.getException();
15.178 + * }
15.179 + * ...normal code here...
15.180 + * }}</pre>
15.181 + *
15.182 + * <p> Be *very* careful in your use of the "privileged" construct, and
15.183 + * always remember to make the privileged code section as small as possible.
15.184 + *
15.185 + * <p> Note that <code>checkPermission</code> always performs security checks
15.186 + * within the context of the currently executing thread.
15.187 + * Sometimes a security check that should be made within a given context
15.188 + * will actually need to be done from within a
15.189 + * <i>different</i> context (for example, from within a worker thread).
15.190 + * The {@link #getContext() getContext} method and
15.191 + * AccessControlContext class are provided
15.192 + * for this situation. The <code>getContext</code> method takes a "snapshot"
15.193 + * of the current calling context, and places
15.194 + * it in an AccessControlContext object, which it returns. A sample call is
15.195 + * the following:
15.196 + *
15.197 + * <pre>
15.198 + *
15.199 + * AccessControlContext acc = AccessController.getContext()
15.200 + *
15.201 + * </pre>
15.202 + *
15.203 + * <p>
15.204 + * AccessControlContext itself has a <code>checkPermission</code> method
15.205 + * that makes access decisions based on the context <i>it</i> encapsulates,
15.206 + * rather than that of the current execution thread.
15.207 + * Code within a different context can thus call that method on the
15.208 + * previously-saved AccessControlContext object. A sample call is the
15.209 + * following:
15.210 + *
15.211 + * <pre>
15.212 + *
15.213 + * acc.checkPermission(permission)
15.214 + *
15.215 + * </pre>
15.216 + *
15.217 + * <p> There are also times where you don't know a priori which permissions
15.218 + * to check the context against. In these cases you can use the
15.219 + * doPrivileged method that takes a context:
15.220 + *
15.221 + * <pre> {@code
15.222 + * somemethod() {
15.223 + * AccessController.doPrivileged(new PrivilegedAction<Object>() {
15.224 + * public Object run() {
15.225 + * // Code goes here. Any permission checks within this
15.226 + * // run method will require that the intersection of the
15.227 + * // callers protection domain and the snapshot's
15.228 + * // context have the desired permission.
15.229 + * }
15.230 + * }, acc);
15.231 + * ...normal code here...
15.232 + * }}</pre>
15.233 + *
15.234 + * @see AccessControlContext
15.235 + *
15.236 + * @author Li Gong
15.237 + * @author Roland Schemers
15.238 + */
15.239 +
15.240 +public final class AccessController {
15.241 +
15.242 + /**
15.243 + * Don't allow anyone to instantiate an AccessController
15.244 + */
15.245 + private AccessController() { }
15.246 +
15.247 + /**
15.248 + * Performs the specified <code>PrivilegedAction</code> with privileges
15.249 + * enabled. The action is performed with <i>all</i> of the permissions
15.250 + * possessed by the caller's protection domain.
15.251 + *
15.252 + * <p> If the action's <code>run</code> method throws an (unchecked)
15.253 + * exception, it will propagate through this method.
15.254 + *
15.255 + * <p> Note that any DomainCombiner associated with the current
15.256 + * AccessControlContext will be ignored while the action is performed.
15.257 + *
15.258 + * @param action the action to be performed.
15.259 + *
15.260 + * @return the value returned by the action's <code>run</code> method.
15.261 + *
15.262 + * @exception NullPointerException if the action is <code>null</code>
15.263 + *
15.264 + * @see #doPrivileged(PrivilegedAction,AccessControlContext)
15.265 + * @see #doPrivileged(PrivilegedExceptionAction)
15.266 + * @see #doPrivilegedWithCombiner(PrivilegedAction)
15.267 + * @see java.security.DomainCombiner
15.268 + */
15.269 +
15.270 + public static native <T> T doPrivileged(PrivilegedAction<T> action);
15.271 +
15.272 + /**
15.273 + * Performs the specified <code>PrivilegedAction</code> with privileges
15.274 + * enabled. The action is performed with <i>all</i> of the permissions
15.275 + * possessed by the caller's protection domain.
15.276 + *
15.277 + * <p> If the action's <code>run</code> method throws an (unchecked)
15.278 + * exception, it will propagate through this method.
15.279 + *
15.280 + * <p> This method preserves the current AccessControlContext's
15.281 + * DomainCombiner (which may be null) while the action is performed.
15.282 + *
15.283 + * @param action the action to be performed.
15.284 + *
15.285 + * @return the value returned by the action's <code>run</code> method.
15.286 + *
15.287 + * @exception NullPointerException if the action is <code>null</code>
15.288 + *
15.289 + * @see #doPrivileged(PrivilegedAction)
15.290 + * @see java.security.DomainCombiner
15.291 + *
15.292 + * @since 1.6
15.293 + */
15.294 + public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
15.295 +
15.296 + DomainCombiner dc = null;
15.297 + AccessControlContext acc = getStackAccessControlContext();
15.298 + if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
15.299 + return AccessController.doPrivileged(action);
15.300 + }
15.301 + return AccessController.doPrivileged(action, preserveCombiner(dc));
15.302 + }
15.303 +
15.304 +
15.305 + /**
15.306 + * Performs the specified <code>PrivilegedAction</code> with privileges
15.307 + * enabled and restricted by the specified
15.308 + * <code>AccessControlContext</code>.
15.309 + * The action is performed with the intersection of the permissions
15.310 + * possessed by the caller's protection domain, and those possessed
15.311 + * by the domains represented by the specified
15.312 + * <code>AccessControlContext</code>.
15.313 + * <p>
15.314 + * If the action's <code>run</code> method throws an (unchecked) exception,
15.315 + * it will propagate through this method.
15.316 + *
15.317 + * @param action the action to be performed.
15.318 + * @param context an <i>access control context</i>
15.319 + * representing the restriction to be applied to the
15.320 + * caller's domain's privileges before performing
15.321 + * the specified action. If the context is
15.322 + * <code>null</code>,
15.323 + * then no additional restriction is applied.
15.324 + *
15.325 + * @return the value returned by the action's <code>run</code> method.
15.326 + *
15.327 + * @exception NullPointerException if the action is <code>null</code>
15.328 + *
15.329 + * @see #doPrivileged(PrivilegedAction)
15.330 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
15.331 + */
15.332 + public static native <T> T doPrivileged(PrivilegedAction<T> action,
15.333 + AccessControlContext context);
15.334 +
15.335 + /**
15.336 + * Performs the specified <code>PrivilegedExceptionAction</code> with
15.337 + * privileges enabled. The action is performed with <i>all</i> of the
15.338 + * permissions possessed by the caller's protection domain.
15.339 + *
15.340 + * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
15.341 + * exception, it will propagate through this method.
15.342 + *
15.343 + * <p> Note that any DomainCombiner associated with the current
15.344 + * AccessControlContext will be ignored while the action is performed.
15.345 + *
15.346 + * @param action the action to be performed
15.347 + *
15.348 + * @return the value returned by the action's <code>run</code> method
15.349 + *
15.350 + * @exception PrivilegedActionException if the specified action's
15.351 + * <code>run</code> method threw a <i>checked</i> exception
15.352 + * @exception NullPointerException if the action is <code>null</code>
15.353 + *
15.354 + * @see #doPrivileged(PrivilegedAction)
15.355 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
15.356 + * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
15.357 + * @see java.security.DomainCombiner
15.358 + */
15.359 + public static native <T> T
15.360 + doPrivileged(PrivilegedExceptionAction<T> action)
15.361 + throws PrivilegedActionException;
15.362 +
15.363 +
15.364 + /**
15.365 + * Performs the specified <code>PrivilegedExceptionAction</code> with
15.366 + * privileges enabled. The action is performed with <i>all</i> of the
15.367 + * permissions possessed by the caller's protection domain.
15.368 + *
15.369 + * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
15.370 + * exception, it will propagate through this method.
15.371 + *
15.372 + * <p> This method preserves the current AccessControlContext's
15.373 + * DomainCombiner (which may be null) while the action is performed.
15.374 + *
15.375 + * @param action the action to be performed.
15.376 + *
15.377 + * @return the value returned by the action's <code>run</code> method
15.378 + *
15.379 + * @exception PrivilegedActionException if the specified action's
15.380 + * <code>run</code> method threw a <i>checked</i> exception
15.381 + * @exception NullPointerException if the action is <code>null</code>
15.382 + *
15.383 + * @see #doPrivileged(PrivilegedAction)
15.384 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
15.385 + * @see java.security.DomainCombiner
15.386 + *
15.387 + * @since 1.6
15.388 + */
15.389 + public static <T> T doPrivilegedWithCombiner
15.390 + (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
15.391 +
15.392 + DomainCombiner dc = null;
15.393 + AccessControlContext acc = getStackAccessControlContext();
15.394 + if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
15.395 + return AccessController.doPrivileged(action);
15.396 + }
15.397 + return AccessController.doPrivileged(action, preserveCombiner(dc));
15.398 + }
15.399 +
15.400 + /**
15.401 + * preserve the combiner across the doPrivileged call
15.402 + */
15.403 + private static AccessControlContext preserveCombiner
15.404 + (DomainCombiner combiner) {
15.405 +
15.406 + /**
15.407 + * callerClass[0] = Reflection.getCallerClass
15.408 + * callerClass[1] = AccessController.preserveCombiner
15.409 + * callerClass[2] = AccessController.doPrivileged
15.410 + * callerClass[3] = caller
15.411 + */
15.412 + final Class callerClass = sun.reflect.Reflection.getCallerClass(3);
15.413 + ProtectionDomain callerPd = doPrivileged
15.414 + (new PrivilegedAction<ProtectionDomain>() {
15.415 + public ProtectionDomain run() {
15.416 + return callerClass.getProtectionDomain();
15.417 + }
15.418 + });
15.419 +
15.420 + // perform 'combine' on the caller of doPrivileged,
15.421 + // even if the caller is from the bootclasspath
15.422 + ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
15.423 + return new AccessControlContext(combiner.combine(pds, null), combiner);
15.424 + }
15.425 +
15.426 +
15.427 + /**
15.428 + * Performs the specified <code>PrivilegedExceptionAction</code> with
15.429 + * privileges enabled and restricted by the specified
15.430 + * <code>AccessControlContext</code>. The action is performed with the
15.431 + * intersection of the permissions possessed by the caller's
15.432 + * protection domain, and those possessed by the domains represented by the
15.433 + * specified <code>AccessControlContext</code>.
15.434 + * <p>
15.435 + * If the action's <code>run</code> method throws an <i>unchecked</i>
15.436 + * exception, it will propagate through this method.
15.437 + *
15.438 + * @param action the action to be performed
15.439 + * @param context an <i>access control context</i>
15.440 + * representing the restriction to be applied to the
15.441 + * caller's domain's privileges before performing
15.442 + * the specified action. If the context is
15.443 + * <code>null</code>,
15.444 + * then no additional restriction is applied.
15.445 + *
15.446 + * @return the value returned by the action's <code>run</code> method
15.447 + *
15.448 + * @exception PrivilegedActionException if the specified action's
15.449 + * <code>run</code> method
15.450 + * threw a <i>checked</i> exception
15.451 + * @exception NullPointerException if the action is <code>null</code>
15.452 + *
15.453 + * @see #doPrivileged(PrivilegedAction)
15.454 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
15.455 + */
15.456 + public static native <T> T
15.457 + doPrivileged(PrivilegedExceptionAction<T> action,
15.458 + AccessControlContext context)
15.459 + throws PrivilegedActionException;
15.460 +
15.461 + /**
15.462 + * Returns the AccessControl context. i.e., it gets
15.463 + * the protection domains of all the callers on the stack,
15.464 + * starting at the first class with a non-null
15.465 + * ProtectionDomain.
15.466 + *
15.467 + * @return the access control context based on the current stack or
15.468 + * null if there was only privileged system code.
15.469 + */
15.470 +
15.471 + private static native AccessControlContext getStackAccessControlContext();
15.472 +
15.473 + /**
15.474 + * Returns the "inherited" AccessControl context. This is the context
15.475 + * that existed when the thread was created. Package private so
15.476 + * AccessControlContext can use it.
15.477 + */
15.478 +
15.479 + static native AccessControlContext getInheritedAccessControlContext();
15.480 +
15.481 + /**
15.482 + * This method takes a "snapshot" of the current calling context, which
15.483 + * includes the current Thread's inherited AccessControlContext,
15.484 + * and places it in an AccessControlContext object. This context may then
15.485 + * be checked at a later point, possibly in another thread.
15.486 + *
15.487 + * @see AccessControlContext
15.488 + *
15.489 + * @return the AccessControlContext based on the current context.
15.490 + */
15.491 +
15.492 + public static AccessControlContext getContext()
15.493 + {
15.494 + AccessControlContext acc = getStackAccessControlContext();
15.495 + if (acc == null) {
15.496 + // all we had was privileged system code. We don't want
15.497 + // to return null though, so we construct a real ACC.
15.498 + return new AccessControlContext(null, true);
15.499 + } else {
15.500 + return acc.optimize();
15.501 + }
15.502 + }
15.503 +
15.504 + /**
15.505 + * Determines whether the access request indicated by the
15.506 + * specified permission should be allowed or denied, based on
15.507 + * the current AccessControlContext and security policy.
15.508 + * This method quietly returns if the access request
15.509 + * is permitted, or throws an AccessControlException otherwise. The
15.510 + * getPermission method of the AccessControlException returns the
15.511 + * <code>perm</code> Permission object instance.
15.512 + *
15.513 + * @param perm the requested permission.
15.514 + *
15.515 + * @exception AccessControlException if the specified permission
15.516 + * is not permitted, based on the current security policy.
15.517 + * @exception NullPointerException if the specified permission
15.518 + * is <code>null</code> and is checked based on the
15.519 + * security policy currently in effect.
15.520 + */
15.521 +
15.522 + public static void checkPermission(Permission perm)
15.523 + throws AccessControlException
15.524 + {
15.525 + //System.err.println("checkPermission "+perm);
15.526 + //Thread.currentThread().dumpStack();
15.527 +
15.528 + if (perm == null) {
15.529 + throw new NullPointerException("permission can't be null");
15.530 + }
15.531 +
15.532 + AccessControlContext stack = getStackAccessControlContext();
15.533 + // if context is null, we had privileged system code on the stack.
15.534 + if (stack == null) {
15.535 + Debug debug = AccessControlContext.getDebug();
15.536 + boolean dumpDebug = false;
15.537 + if (debug != null) {
15.538 + dumpDebug = !Debug.isOn("codebase=");
15.539 + dumpDebug &= !Debug.isOn("permission=") ||
15.540 + Debug.isOn("permission=" + perm.getClass().getCanonicalName());
15.541 + }
15.542 +
15.543 + if (dumpDebug && Debug.isOn("stack")) {
15.544 + Thread.currentThread().dumpStack();
15.545 + }
15.546 +
15.547 + if (dumpDebug && Debug.isOn("domain")) {
15.548 + debug.println("domain (context is null)");
15.549 + }
15.550 +
15.551 + if (dumpDebug) {
15.552 + debug.println("access allowed "+perm);
15.553 + }
15.554 + return;
15.555 + }
15.556 +
15.557 + AccessControlContext acc = stack.optimize();
15.558 + acc.checkPermission(perm);
15.559 + }
15.560 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedAction.java Thu Oct 03 15:40:35 2013 +0200
16.3 @@ -0,0 +1,56 @@
16.4 +/*
16.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
16.7 + *
16.8 + * This code is free software; you can redistribute it and/or modify it
16.9 + * under the terms of the GNU General Public License version 2 only, as
16.10 + * published by the Free Software Foundation. Oracle designates this
16.11 + * particular file as subject to the "Classpath" exception as provided
16.12 + * by Oracle in the LICENSE file that accompanied this code.
16.13 + *
16.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
16.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16.17 + * version 2 for more details (a copy is included in the LICENSE file that
16.18 + * accompanied this code).
16.19 + *
16.20 + * You should have received a copy of the GNU General Public License version
16.21 + * 2 along with this work; if not, write to the Free Software Foundation,
16.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
16.23 + *
16.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
16.25 + * or visit www.oracle.com if you need additional information or have any
16.26 + * questions.
16.27 + */
16.28 +
16.29 +package java.security;
16.30 +
16.31 +
16.32 +/**
16.33 + * A computation to be performed with privileges enabled. The computation is
16.34 + * performed by invoking <code>AccessController.doPrivileged</code> on the
16.35 + * <code>PrivilegedAction</code> object. This interface is used only for
16.36 + * computations that do not throw checked exceptions; computations that
16.37 + * throw checked exceptions must use <code>PrivilegedExceptionAction</code>
16.38 + * instead.
16.39 + *
16.40 + * @see AccessController
16.41 + * @see AccessController#doPrivileged(PrivilegedAction)
16.42 + * @see PrivilegedExceptionAction
16.43 + */
16.44 +
16.45 +public interface PrivilegedAction<T> {
16.46 + /**
16.47 + * Performs the computation. This method will be called by
16.48 + * <code>AccessController.doPrivileged</code> after enabling privileges.
16.49 + *
16.50 + * @return a class-dependent value that may represent the results of the
16.51 + * computation. Each class that implements
16.52 + * <code>PrivilegedAction</code>
16.53 + * should document what (if anything) this value represents.
16.54 + * @see AccessController#doPrivileged(PrivilegedAction)
16.55 + * @see AccessController#doPrivileged(PrivilegedAction,
16.56 + * AccessControlContext)
16.57 + */
16.58 + T run();
16.59 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedActionException.java Thu Oct 03 15:40:35 2013 +0200
17.3 @@ -0,0 +1,105 @@
17.4 +/*
17.5 + * Copyright (c) 1998, 2001, 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 +/**
17.32 + * This exception is thrown by
17.33 + * <code>doPrivileged(PrivilegedExceptionAction)</code> and
17.34 + * <code>doPrivileged(PrivilegedExceptionAction,
17.35 + * AccessControlContext context)</code> to indicate
17.36 + * that the action being performed threw a checked exception. The exception
17.37 + * thrown by the action can be obtained by calling the
17.38 + * <code>getException</code> method. In effect, an
17.39 + * <code>PrivilegedActionException</code> is a "wrapper"
17.40 + * for an exception thrown by a privileged action.
17.41 + *
17.42 + * <p>As of release 1.4, this exception has been retrofitted to conform to
17.43 + * the general purpose exception-chaining mechanism. The "exception thrown
17.44 + * by the privileged computation" that is provided at construction time and
17.45 + * accessed via the {@link #getException()} method is now known as the
17.46 + * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
17.47 + * method, as well as the aforementioned "legacy method."
17.48 + *
17.49 + * @see PrivilegedExceptionAction
17.50 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
17.51 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
17.52 + */
17.53 +public class PrivilegedActionException extends Exception {
17.54 + // use serialVersionUID from JDK 1.2.2 for interoperability
17.55 + private static final long serialVersionUID = 4724086851538908602L;
17.56 +
17.57 + /**
17.58 + * @serial
17.59 + */
17.60 + private Exception exception;
17.61 +
17.62 + /**
17.63 + * Constructs a new PrivilegedActionException "wrapping"
17.64 + * the specific Exception.
17.65 + *
17.66 + * @param exception The exception thrown
17.67 + */
17.68 + public PrivilegedActionException(Exception exception) {
17.69 + super((Throwable)null); // Disallow initCause
17.70 + this.exception = exception;
17.71 + }
17.72 +
17.73 + /**
17.74 + * Returns the exception thrown by the privileged computation that
17.75 + * resulted in this <code>PrivilegedActionException</code>.
17.76 + *
17.77 + * <p>This method predates the general-purpose exception chaining facility.
17.78 + * The {@link Throwable#getCause()} method is now the preferred means of
17.79 + * obtaining this information.
17.80 + *
17.81 + * @return the exception thrown by the privileged computation that
17.82 + * resulted in this <code>PrivilegedActionException</code>.
17.83 + * @see PrivilegedExceptionAction
17.84 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
17.85 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
17.86 + * AccessControlContext)
17.87 + */
17.88 + public Exception getException() {
17.89 + return exception;
17.90 + }
17.91 +
17.92 + /**
17.93 + * Returns the cause of this exception (the exception thrown by
17.94 + * the privileged computation that resulted in this
17.95 + * <code>PrivilegedActionException</code>).
17.96 + *
17.97 + * @return the cause of this exception.
17.98 + * @since 1.4
17.99 + */
17.100 + public Throwable getCause() {
17.101 + return exception;
17.102 + }
17.103 +
17.104 + public String toString() {
17.105 + String s = getClass().getName();
17.106 + return (exception != null) ? (s + ": " + exception.toString()) : s;
17.107 + }
17.108 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedExceptionAction.java Thu Oct 03 15:40:35 2013 +0200
18.3 @@ -0,0 +1,62 @@
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, that throws one or
18.34 + * more checked exceptions. The computation is performed by invoking
18.35 + * <code>AccessController.doPrivileged</code> on the
18.36 + * <code>PrivilegedExceptionAction</code> object. This interface is
18.37 + * used only for computations that throw checked exceptions;
18.38 + * computations that do not throw
18.39 + * checked exceptions should use <code>PrivilegedAction</code> instead.
18.40 + *
18.41 + * @see AccessController
18.42 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
18.43 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
18.44 + * AccessControlContext)
18.45 + * @see PrivilegedAction
18.46 + */
18.47 +
18.48 +public interface PrivilegedExceptionAction<T> {
18.49 + /**
18.50 + * Performs the computation. This method will be called by
18.51 + * <code>AccessController.doPrivileged</code> after enabling privileges.
18.52 + *
18.53 + * @return a class-dependent value that may represent the results of the
18.54 + * computation. Each class that implements
18.55 + * <code>PrivilegedExceptionAction</code> should document what
18.56 + * (if anything) this value represents.
18.57 + * @throws Exception an exceptional condition has occurred. Each class
18.58 + * that implements <code>PrivilegedExceptionAction</code> should
18.59 + * document the exceptions that its run method can throw.
18.60 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
18.61 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
18.62 + */
18.63 +
18.64 + T run() throws Exception;
18.65 +}
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/rt/emul/compact/src/main/java/java/text/Annotation.java Thu Oct 03 15:40:35 2013 +0200
19.3 @@ -0,0 +1,84 @@
19.4 +/*
19.5 + * Copyright (c) 1997, 2002, 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.text;
19.30 +
19.31 +/**
19.32 +* An Annotation object is used as a wrapper for a text attribute value if
19.33 +* the attribute has annotation characteristics. These characteristics are:
19.34 +* <ul>
19.35 +* <li>The text range that the attribute is applied to is critical to the
19.36 +* semantics of the range. That means, the attribute cannot be applied to subranges
19.37 +* of the text range that it applies to, and, if two adjacent text ranges have
19.38 +* the same value for this attribute, the attribute still cannot be applied to
19.39 +* the combined range as a whole with this value.
19.40 +* <li>The attribute or its value usually do no longer apply if the underlying text is
19.41 +* changed.
19.42 +* </ul>
19.43 +*
19.44 +* An example is grammatical information attached to a sentence:
19.45 +* For the previous sentence, you can say that "an example"
19.46 +* is the subject, but you cannot say the same about "an", "example", or "exam".
19.47 +* When the text is changed, the grammatical information typically becomes invalid.
19.48 +* Another example is Japanese reading information (yomi).
19.49 +*
19.50 +* <p>
19.51 +* Wrapping the attribute value into an Annotation object guarantees that
19.52 +* adjacent text runs don't get merged even if the attribute values are equal,
19.53 +* and indicates to text containers that the attribute should be discarded if
19.54 +* the underlying text is modified.
19.55 +*
19.56 +* @see AttributedCharacterIterator
19.57 +* @since 1.2
19.58 +*/
19.59 +
19.60 +public class Annotation {
19.61 +
19.62 + /**
19.63 + * Constructs an annotation record with the given value, which
19.64 + * may be null.
19.65 + * @param value The value of the attribute
19.66 + */
19.67 + public Annotation(Object value) {
19.68 + this.value = value;
19.69 + }
19.70 +
19.71 + /**
19.72 + * Returns the value of the attribute, which may be null.
19.73 + */
19.74 + public Object getValue() {
19.75 + return value;
19.76 + }
19.77 +
19.78 + /**
19.79 + * Returns the String representation of this Annotation.
19.80 + */
19.81 + public String toString() {
19.82 + return getClass().getName() + "[value=" + value + "]";
19.83 + }
19.84 +
19.85 + private Object value;
19.86 +
19.87 +};
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedCharacterIterator.java Thu Oct 03 15:40:35 2013 +0200
20.3 @@ -0,0 +1,254 @@
20.4 +/*
20.5 + * Copyright (c) 1997, 2010, 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.text;
20.30 +
20.31 +import java.io.InvalidObjectException;
20.32 +import java.io.Serializable;
20.33 +import java.util.HashMap;
20.34 +import java.util.Map;
20.35 +import java.util.Set;
20.36 +
20.37 +/**
20.38 + * An {@code AttributedCharacterIterator} allows iteration through both text and
20.39 + * related attribute information.
20.40 + *
20.41 + * <p>
20.42 + * An attribute is a key/value pair, identified by the key. No two
20.43 + * attributes on a given character can have the same key.
20.44 + *
20.45 + * <p>The values for an attribute are immutable, or must not be mutated
20.46 + * by clients or storage. They are always passed by reference, and not
20.47 + * cloned.
20.48 + *
20.49 + * <p>A <em>run with respect to an attribute</em> is a maximum text range for
20.50 + * which:
20.51 + * <ul>
20.52 + * <li>the attribute is undefined or {@code null} for the entire range, or
20.53 + * <li>the attribute value is defined and has the same non-{@code null} value for the
20.54 + * entire range.
20.55 + * </ul>
20.56 + *
20.57 + * <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
20.58 + * which this condition is met for each member attribute.
20.59 + *
20.60 + * <p>When getting a run with no explicit attributes specified (i.e.,
20.61 + * calling {@link #getRunStart()} and {@link #getRunLimit()}), any
20.62 + * contiguous text segments having the same attributes (the same set
20.63 + * of attribute/value pairs) are treated as separate runs if the
20.64 + * attributes have been given to those text segments separately.
20.65 + *
20.66 + * <p>The returned indexes are limited to the range of the iterator.
20.67 + *
20.68 + * <p>The returned attribute information is limited to runs that contain
20.69 + * the current character.
20.70 + *
20.71 + * <p>
20.72 + * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
20.73 + * subclasses, such as {@link java.awt.font.TextAttribute}.
20.74 + *
20.75 + * @see AttributedCharacterIterator.Attribute
20.76 + * @see java.awt.font.TextAttribute
20.77 + * @see AttributedString
20.78 + * @see Annotation
20.79 + * @since 1.2
20.80 + */
20.81 +
20.82 +public interface AttributedCharacterIterator extends CharacterIterator {
20.83 +
20.84 + /**
20.85 + * Defines attribute keys that are used to identify text attributes. These
20.86 + * keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
20.87 + * @see AttributedCharacterIterator
20.88 + * @see AttributedString
20.89 + * @since 1.2
20.90 + */
20.91 +
20.92 + public static class Attribute implements Serializable {
20.93 +
20.94 + /**
20.95 + * The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
20.96 + * to look up the corresponding predefined instance when deserializing
20.97 + * an instance.
20.98 + * @serial
20.99 + */
20.100 + private String name;
20.101 +
20.102 + // table of all instances in this class, used by readResolve
20.103 + private static final Map instanceMap = new HashMap(7);
20.104 +
20.105 + /**
20.106 + * Constructs an {@code Attribute} with the given name.
20.107 + */
20.108 + protected Attribute(String name) {
20.109 + this.name = name;
20.110 + if (this.getClass() == Attribute.class) {
20.111 + instanceMap.put(name, this);
20.112 + }
20.113 + }
20.114 +
20.115 + /**
20.116 + * Compares two objects for equality. This version only returns true
20.117 + * for <code>x.equals(y)</code> if <code>x</code> and <code>y</code> refer
20.118 + * to the same object, and guarantees this for all subclasses.
20.119 + */
20.120 + public final boolean equals(Object obj) {
20.121 + return super.equals(obj);
20.122 + }
20.123 +
20.124 + /**
20.125 + * Returns a hash code value for the object. This version is identical to
20.126 + * the one in {@code Object}, but is also final.
20.127 + */
20.128 + public final int hashCode() {
20.129 + return super.hashCode();
20.130 + }
20.131 +
20.132 + /**
20.133 + * Returns a string representation of the object. This version returns the
20.134 + * concatenation of class name, {@code "("}, a name identifying the attribute
20.135 + * and {@code ")"}.
20.136 + */
20.137 + public String toString() {
20.138 + return getClass().getName() + "(" + name + ")";
20.139 + }
20.140 +
20.141 + /**
20.142 + * Returns the name of the attribute.
20.143 + */
20.144 + protected String getName() {
20.145 + return name;
20.146 + }
20.147 +
20.148 + /**
20.149 + * Resolves instances being deserialized to the predefined constants.
20.150 + */
20.151 + protected Object readResolve() throws InvalidObjectException {
20.152 + if (this.getClass() != Attribute.class) {
20.153 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
20.154 + }
20.155 +
20.156 + Attribute instance = (Attribute) instanceMap.get(getName());
20.157 + if (instance != null) {
20.158 + return instance;
20.159 + } else {
20.160 + throw new InvalidObjectException("unknown attribute name");
20.161 + }
20.162 + }
20.163 +
20.164 + /**
20.165 + * Attribute key for the language of some text.
20.166 + * <p> Values are instances of {@link java.util.Locale Locale}.
20.167 + * @see java.util.Locale
20.168 + */
20.169 + public static final Attribute LANGUAGE = new Attribute("language");
20.170 +
20.171 + /**
20.172 + * Attribute key for the reading of some text. In languages where the written form
20.173 + * and the pronunciation of a word are only loosely related (such as Japanese),
20.174 + * it is often necessary to store the reading (pronunciation) along with the
20.175 + * written form.
20.176 + * <p>Values are instances of {@link Annotation} holding instances of {@link String}.
20.177 + * @see Annotation
20.178 + * @see java.lang.String
20.179 + */
20.180 + public static final Attribute READING = new Attribute("reading");
20.181 +
20.182 + /**
20.183 + * Attribute key for input method segments. Input methods often break
20.184 + * up text into segments, which usually correspond to words.
20.185 + * <p>Values are instances of {@link Annotation} holding a {@code null} reference.
20.186 + * @see Annotation
20.187 + */
20.188 + public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
20.189 +
20.190 + // make sure the serial version doesn't change between compiler versions
20.191 + private static final long serialVersionUID = -9142742483513960612L;
20.192 +
20.193 + };
20.194 +
20.195 + /**
20.196 + * Returns the index of the first character of the run
20.197 + * with respect to all attributes containing the current character.
20.198 + *
20.199 + * <p>Any contiguous text segments having the same attributes (the
20.200 + * same set of attribute/value pairs) are treated as separate runs
20.201 + * if the attributes have been given to those text segments separately.
20.202 + */
20.203 + public int getRunStart();
20.204 +
20.205 + /**
20.206 + * Returns the index of the first character of the run
20.207 + * with respect to the given {@code attribute} containing the current character.
20.208 + */
20.209 + public int getRunStart(Attribute attribute);
20.210 +
20.211 + /**
20.212 + * Returns the index of the first character of the run
20.213 + * with respect to the given {@code attributes} containing the current character.
20.214 + */
20.215 + public int getRunStart(Set<? extends Attribute> attributes);
20.216 +
20.217 + /**
20.218 + * Returns the index of the first character following the run
20.219 + * with respect to all attributes containing the current character.
20.220 + *
20.221 + * <p>Any contiguous text segments having the same attributes (the
20.222 + * same set of attribute/value pairs) are treated as separate runs
20.223 + * if the attributes have been given to those text segments separately.
20.224 + */
20.225 + public int getRunLimit();
20.226 +
20.227 + /**
20.228 + * Returns the index of the first character following the run
20.229 + * with respect to the given {@code attribute} containing the current character.
20.230 + */
20.231 + public int getRunLimit(Attribute attribute);
20.232 +
20.233 + /**
20.234 + * Returns the index of the first character following the run
20.235 + * with respect to the given {@code attributes} containing the current character.
20.236 + */
20.237 + public int getRunLimit(Set<? extends Attribute> attributes);
20.238 +
20.239 + /**
20.240 + * Returns a map with the attributes defined on the current
20.241 + * character.
20.242 + */
20.243 + public Map<Attribute,Object> getAttributes();
20.244 +
20.245 + /**
20.246 + * Returns the value of the named {@code attribute} for the current character.
20.247 + * Returns {@code null} if the {@code attribute} is not defined.
20.248 + */
20.249 + public Object getAttribute(Attribute attribute);
20.250 +
20.251 + /**
20.252 + * Returns the keys of all attributes defined on the
20.253 + * iterator's text range. The set is empty if no
20.254 + * attributes are defined.
20.255 + */
20.256 + public Set<Attribute> getAllAttributeKeys();
20.257 +};
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedString.java Thu Oct 03 15:40:35 2013 +0200
21.3 @@ -0,0 +1,1120 @@
21.4 +/*
21.5 + * Copyright (c) 1997, 2006, 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 +import java.util.*;
21.32 +import java.text.AttributedCharacterIterator.Attribute;
21.33 +
21.34 +/**
21.35 + * An AttributedString holds text and related attribute information. It
21.36 + * may be used as the actual data storage in some cases where a text
21.37 + * reader wants to access attributed text through the AttributedCharacterIterator
21.38 + * interface.
21.39 + *
21.40 + * <p>
21.41 + * An attribute is a key/value pair, identified by the key. No two
21.42 + * attributes on a given character can have the same key.
21.43 + *
21.44 + * <p>The values for an attribute are immutable, or must not be mutated
21.45 + * by clients or storage. They are always passed by reference, and not
21.46 + * cloned.
21.47 + *
21.48 + * @see AttributedCharacterIterator
21.49 + * @see Annotation
21.50 + * @since 1.2
21.51 + */
21.52 +
21.53 +public class AttributedString {
21.54 +
21.55 + // since there are no vectors of int, we have to use arrays.
21.56 + // We allocate them in chunks of 10 elements so we don't have to allocate all the time.
21.57 + private static final int ARRAY_SIZE_INCREMENT = 10;
21.58 +
21.59 + // field holding the text
21.60 + String text;
21.61 +
21.62 + // fields holding run attribute information
21.63 + // run attributes are organized by run
21.64 + int runArraySize; // current size of the arrays
21.65 + int runCount; // actual number of runs, <= runArraySize
21.66 + int runStarts[]; // start index for each run
21.67 + Vector runAttributes[]; // vector of attribute keys for each run
21.68 + Vector runAttributeValues[]; // parallel vector of attribute values for each run
21.69 +
21.70 + /**
21.71 + * Constructs an AttributedString instance with the given
21.72 + * AttributedCharacterIterators.
21.73 + *
21.74 + * @param iterators AttributedCharacterIterators to construct
21.75 + * AttributedString from.
21.76 + * @throws NullPointerException if iterators is null
21.77 + */
21.78 + AttributedString(AttributedCharacterIterator[] iterators) {
21.79 + if (iterators == null) {
21.80 + throw new NullPointerException("Iterators must not be null");
21.81 + }
21.82 + if (iterators.length == 0) {
21.83 + text = "";
21.84 + }
21.85 + else {
21.86 + // Build the String contents
21.87 + StringBuffer buffer = new StringBuffer();
21.88 + for (int counter = 0; counter < iterators.length; counter++) {
21.89 + appendContents(buffer, iterators[counter]);
21.90 + }
21.91 +
21.92 + text = buffer.toString();
21.93 +
21.94 + if (text.length() > 0) {
21.95 + // Determine the runs, creating a new run when the attributes
21.96 + // differ.
21.97 + int offset = 0;
21.98 + Map last = null;
21.99 +
21.100 + for (int counter = 0; counter < iterators.length; counter++) {
21.101 + AttributedCharacterIterator iterator = iterators[counter];
21.102 + int start = iterator.getBeginIndex();
21.103 + int end = iterator.getEndIndex();
21.104 + int index = start;
21.105 +
21.106 + while (index < end) {
21.107 + iterator.setIndex(index);
21.108 +
21.109 + Map attrs = iterator.getAttributes();
21.110 +
21.111 + if (mapsDiffer(last, attrs)) {
21.112 + setAttributes(attrs, index - start + offset);
21.113 + }
21.114 + last = attrs;
21.115 + index = iterator.getRunLimit();
21.116 + }
21.117 + offset += (end - start);
21.118 + }
21.119 + }
21.120 + }
21.121 + }
21.122 +
21.123 + /**
21.124 + * Constructs an AttributedString instance with the given text.
21.125 + * @param text The text for this attributed string.
21.126 + * @exception NullPointerException if <code>text</code> is null.
21.127 + */
21.128 + public AttributedString(String text) {
21.129 + if (text == null) {
21.130 + throw new NullPointerException();
21.131 + }
21.132 + this.text = text;
21.133 + }
21.134 +
21.135 + /**
21.136 + * Constructs an AttributedString instance with the given text and attributes.
21.137 + * @param text The text for this attributed string.
21.138 + * @param attributes The attributes that apply to the entire string.
21.139 + * @exception NullPointerException if <code>text</code> or
21.140 + * <code>attributes</code> is null.
21.141 + * @exception IllegalArgumentException if the text has length 0
21.142 + * and the attributes parameter is not an empty Map (attributes
21.143 + * cannot be applied to a 0-length range).
21.144 + */
21.145 + public AttributedString(String text,
21.146 + Map<? extends Attribute, ?> attributes)
21.147 + {
21.148 + if (text == null || attributes == null) {
21.149 + throw new NullPointerException();
21.150 + }
21.151 + this.text = text;
21.152 +
21.153 + if (text.length() == 0) {
21.154 + if (attributes.isEmpty())
21.155 + return;
21.156 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
21.157 + }
21.158 +
21.159 + int attributeCount = attributes.size();
21.160 + if (attributeCount > 0) {
21.161 + createRunAttributeDataVectors();
21.162 + Vector newRunAttributes = new Vector(attributeCount);
21.163 + Vector newRunAttributeValues = new Vector(attributeCount);
21.164 + runAttributes[0] = newRunAttributes;
21.165 + runAttributeValues[0] = newRunAttributeValues;
21.166 + Iterator iterator = attributes.entrySet().iterator();
21.167 + while (iterator.hasNext()) {
21.168 + Map.Entry entry = (Map.Entry) iterator.next();
21.169 + newRunAttributes.addElement(entry.getKey());
21.170 + newRunAttributeValues.addElement(entry.getValue());
21.171 + }
21.172 + }
21.173 + }
21.174 +
21.175 + /**
21.176 + * Constructs an AttributedString instance with the given attributed
21.177 + * text represented by AttributedCharacterIterator.
21.178 + * @param text The text for this attributed string.
21.179 + * @exception NullPointerException if <code>text</code> is null.
21.180 + */
21.181 + public AttributedString(AttributedCharacterIterator text) {
21.182 + // If performance is critical, this constructor should be
21.183 + // implemented here rather than invoking the constructor for a
21.184 + // subrange. We can avoid some range checking in the loops.
21.185 + this(text, text.getBeginIndex(), text.getEndIndex(), null);
21.186 + }
21.187 +
21.188 + /**
21.189 + * Constructs an AttributedString instance with the subrange of
21.190 + * the given attributed text represented by
21.191 + * AttributedCharacterIterator. If the given range produces an
21.192 + * empty text, all attributes will be discarded. Note that any
21.193 + * attributes wrapped by an Annotation object are discarded for a
21.194 + * subrange of the original attribute range.
21.195 + *
21.196 + * @param text The text for this attributed string.
21.197 + * @param beginIndex Index of the first character of the range.
21.198 + * @param endIndex Index of the character following the last character
21.199 + * of the range.
21.200 + * @exception NullPointerException if <code>text</code> is null.
21.201 + * @exception IllegalArgumentException if the subrange given by
21.202 + * beginIndex and endIndex is out of the text range.
21.203 + * @see java.text.Annotation
21.204 + */
21.205 + public AttributedString(AttributedCharacterIterator text,
21.206 + int beginIndex,
21.207 + int endIndex) {
21.208 + this(text, beginIndex, endIndex, null);
21.209 + }
21.210 +
21.211 + /**
21.212 + * Constructs an AttributedString instance with the subrange of
21.213 + * the given attributed text represented by
21.214 + * AttributedCharacterIterator. Only attributes that match the
21.215 + * given attributes will be incorporated into the instance. If the
21.216 + * given range produces an empty text, all attributes will be
21.217 + * discarded. Note that any attributes wrapped by an Annotation
21.218 + * object are discarded for a subrange of the original attribute
21.219 + * range.
21.220 + *
21.221 + * @param text The text for this attributed string.
21.222 + * @param beginIndex Index of the first character of the range.
21.223 + * @param endIndex Index of the character following the last character
21.224 + * of the range.
21.225 + * @param attributes Specifies attributes to be extracted
21.226 + * from the text. If null is specified, all available attributes will
21.227 + * be used.
21.228 + * @exception NullPointerException if <code>text</code> is null.
21.229 + * @exception IllegalArgumentException if the subrange given by
21.230 + * beginIndex and endIndex is out of the text range.
21.231 + * @see java.text.Annotation
21.232 + */
21.233 + public AttributedString(AttributedCharacterIterator text,
21.234 + int beginIndex,
21.235 + int endIndex,
21.236 + Attribute[] attributes) {
21.237 + if (text == null) {
21.238 + throw new NullPointerException();
21.239 + }
21.240 +
21.241 + // Validate the given subrange
21.242 + int textBeginIndex = text.getBeginIndex();
21.243 + int textEndIndex = text.getEndIndex();
21.244 + if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex)
21.245 + throw new IllegalArgumentException("Invalid substring range");
21.246 +
21.247 + // Copy the given string
21.248 + StringBuffer textBuffer = new StringBuffer();
21.249 + text.setIndex(beginIndex);
21.250 + for (char c = text.current(); text.getIndex() < endIndex; c = text.next())
21.251 + textBuffer.append(c);
21.252 + this.text = textBuffer.toString();
21.253 +
21.254 + if (beginIndex == endIndex)
21.255 + return;
21.256 +
21.257 + // Select attribute keys to be taken care of
21.258 + HashSet keys = new HashSet();
21.259 + if (attributes == null) {
21.260 + keys.addAll(text.getAllAttributeKeys());
21.261 + } else {
21.262 + for (int i = 0; i < attributes.length; i++)
21.263 + keys.add(attributes[i]);
21.264 + keys.retainAll(text.getAllAttributeKeys());
21.265 + }
21.266 + if (keys.isEmpty())
21.267 + return;
21.268 +
21.269 + // Get and set attribute runs for each attribute name. Need to
21.270 + // scan from the top of the text so that we can discard any
21.271 + // Annotation that is no longer applied to a subset text segment.
21.272 + Iterator itr = keys.iterator();
21.273 + while (itr.hasNext()) {
21.274 + Attribute attributeKey = (Attribute)itr.next();
21.275 + text.setIndex(textBeginIndex);
21.276 + while (text.getIndex() < endIndex) {
21.277 + int start = text.getRunStart(attributeKey);
21.278 + int limit = text.getRunLimit(attributeKey);
21.279 + Object value = text.getAttribute(attributeKey);
21.280 +
21.281 + if (value != null) {
21.282 + if (value instanceof Annotation) {
21.283 + if (start >= beginIndex && limit <= endIndex) {
21.284 + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
21.285 + } else {
21.286 + if (limit > endIndex)
21.287 + break;
21.288 + }
21.289 + } else {
21.290 + // if the run is beyond the given (subset) range, we
21.291 + // don't need to process further.
21.292 + if (start >= endIndex)
21.293 + break;
21.294 + if (limit > beginIndex) {
21.295 + // attribute is applied to any subrange
21.296 + if (start < beginIndex)
21.297 + start = beginIndex;
21.298 + if (limit > endIndex)
21.299 + limit = endIndex;
21.300 + if (start != limit) {
21.301 + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
21.302 + }
21.303 + }
21.304 + }
21.305 + }
21.306 + text.setIndex(limit);
21.307 + }
21.308 + }
21.309 + }
21.310 +
21.311 + /**
21.312 + * Adds an attribute to the entire string.
21.313 + * @param attribute the attribute key
21.314 + * @param value the value of the attribute; may be null
21.315 + * @exception NullPointerException if <code>attribute</code> is null.
21.316 + * @exception IllegalArgumentException if the AttributedString has length 0
21.317 + * (attributes cannot be applied to a 0-length range).
21.318 + */
21.319 + public void addAttribute(Attribute attribute, Object value) {
21.320 +
21.321 + if (attribute == null) {
21.322 + throw new NullPointerException();
21.323 + }
21.324 +
21.325 + int len = length();
21.326 + if (len == 0) {
21.327 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
21.328 + }
21.329 +
21.330 + addAttributeImpl(attribute, value, 0, len);
21.331 + }
21.332 +
21.333 + /**
21.334 + * Adds an attribute to a subrange of the string.
21.335 + * @param attribute the attribute key
21.336 + * @param value The value of the attribute. May be null.
21.337 + * @param beginIndex Index of the first character of the range.
21.338 + * @param endIndex Index of the character following the last character of the range.
21.339 + * @exception NullPointerException if <code>attribute</code> is null.
21.340 + * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
21.341 + * greater than the length of the string, or beginIndex and endIndex together don't
21.342 + * define a non-empty subrange of the string.
21.343 + */
21.344 + public void addAttribute(Attribute attribute, Object value,
21.345 + int beginIndex, int endIndex) {
21.346 +
21.347 + if (attribute == null) {
21.348 + throw new NullPointerException();
21.349 + }
21.350 +
21.351 + if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) {
21.352 + throw new IllegalArgumentException("Invalid substring range");
21.353 + }
21.354 +
21.355 + addAttributeImpl(attribute, value, beginIndex, endIndex);
21.356 + }
21.357 +
21.358 + /**
21.359 + * Adds a set of attributes to a subrange of the string.
21.360 + * @param attributes The attributes to be added to the string.
21.361 + * @param beginIndex Index of the first character of the range.
21.362 + * @param endIndex Index of the character following the last
21.363 + * character of the range.
21.364 + * @exception NullPointerException if <code>attributes</code> is null.
21.365 + * @exception IllegalArgumentException if beginIndex is less then
21.366 + * 0, endIndex is greater than the length of the string, or
21.367 + * beginIndex and endIndex together don't define a non-empty
21.368 + * subrange of the string and the attributes parameter is not an
21.369 + * empty Map.
21.370 + */
21.371 + public void addAttributes(Map<? extends Attribute, ?> attributes,
21.372 + int beginIndex, int endIndex)
21.373 + {
21.374 + if (attributes == null) {
21.375 + throw new NullPointerException();
21.376 + }
21.377 +
21.378 + if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
21.379 + throw new IllegalArgumentException("Invalid substring range");
21.380 + }
21.381 + if (beginIndex == endIndex) {
21.382 + if (attributes.isEmpty())
21.383 + return;
21.384 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
21.385 + }
21.386 +
21.387 + // make sure we have run attribute data vectors
21.388 + if (runCount == 0) {
21.389 + createRunAttributeDataVectors();
21.390 + }
21.391 +
21.392 + // break up runs if necessary
21.393 + int beginRunIndex = ensureRunBreak(beginIndex);
21.394 + int endRunIndex = ensureRunBreak(endIndex);
21.395 +
21.396 + Iterator iterator = attributes.entrySet().iterator();
21.397 + while (iterator.hasNext()) {
21.398 + Map.Entry entry = (Map.Entry) iterator.next();
21.399 + addAttributeRunData((Attribute) entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex);
21.400 + }
21.401 + }
21.402 +
21.403 + private synchronized void addAttributeImpl(Attribute attribute, Object value,
21.404 + int beginIndex, int endIndex) {
21.405 +
21.406 + // make sure we have run attribute data vectors
21.407 + if (runCount == 0) {
21.408 + createRunAttributeDataVectors();
21.409 + }
21.410 +
21.411 + // break up runs if necessary
21.412 + int beginRunIndex = ensureRunBreak(beginIndex);
21.413 + int endRunIndex = ensureRunBreak(endIndex);
21.414 +
21.415 + addAttributeRunData(attribute, value, beginRunIndex, endRunIndex);
21.416 + }
21.417 +
21.418 + private final void createRunAttributeDataVectors() {
21.419 + // use temporary variables so things remain consistent in case of an exception
21.420 + int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
21.421 + Vector newRunAttributes[] = new Vector[ARRAY_SIZE_INCREMENT];
21.422 + Vector newRunAttributeValues[] = new Vector[ARRAY_SIZE_INCREMENT];
21.423 + runStarts = newRunStarts;
21.424 + runAttributes = newRunAttributes;
21.425 + runAttributeValues = newRunAttributeValues;
21.426 + runArraySize = ARRAY_SIZE_INCREMENT;
21.427 + runCount = 1; // assume initial run starting at index 0
21.428 + }
21.429 +
21.430 + // ensure there's a run break at offset, return the index of the run
21.431 + private final int ensureRunBreak(int offset) {
21.432 + return ensureRunBreak(offset, true);
21.433 + }
21.434 +
21.435 + /**
21.436 + * Ensures there is a run break at offset, returning the index of
21.437 + * the run. If this results in splitting a run, two things can happen:
21.438 + * <ul>
21.439 + * <li>If copyAttrs is true, the attributes from the existing run
21.440 + * will be placed in both of the newly created runs.
21.441 + * <li>If copyAttrs is false, the attributes from the existing run
21.442 + * will NOT be copied to the run to the right (>= offset) of the break,
21.443 + * but will exist on the run to the left (< offset).
21.444 + * </ul>
21.445 + */
21.446 + private final int ensureRunBreak(int offset, boolean copyAttrs) {
21.447 + if (offset == length()) {
21.448 + return runCount;
21.449 + }
21.450 +
21.451 + // search for the run index where this offset should be
21.452 + int runIndex = 0;
21.453 + while (runIndex < runCount && runStarts[runIndex] < offset) {
21.454 + runIndex++;
21.455 + }
21.456 +
21.457 + // if the offset is at a run start already, we're done
21.458 + if (runIndex < runCount && runStarts[runIndex] == offset) {
21.459 + return runIndex;
21.460 + }
21.461 +
21.462 + // we'll have to break up a run
21.463 + // first, make sure we have enough space in our arrays
21.464 + if (runCount == runArraySize) {
21.465 + int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT;
21.466 + int newRunStarts[] = new int[newArraySize];
21.467 + Vector newRunAttributes[] = new Vector[newArraySize];
21.468 + Vector newRunAttributeValues[] = new Vector[newArraySize];
21.469 + for (int i = 0; i < runArraySize; i++) {
21.470 + newRunStarts[i] = runStarts[i];
21.471 + newRunAttributes[i] = runAttributes[i];
21.472 + newRunAttributeValues[i] = runAttributeValues[i];
21.473 + }
21.474 + runStarts = newRunStarts;
21.475 + runAttributes = newRunAttributes;
21.476 + runAttributeValues = newRunAttributeValues;
21.477 + runArraySize = newArraySize;
21.478 + }
21.479 +
21.480 + // make copies of the attribute information of the old run that the new one used to be part of
21.481 + // use temporary variables so things remain consistent in case of an exception
21.482 + Vector newRunAttributes = null;
21.483 + Vector newRunAttributeValues = null;
21.484 +
21.485 + if (copyAttrs) {
21.486 + Vector oldRunAttributes = runAttributes[runIndex - 1];
21.487 + Vector oldRunAttributeValues = runAttributeValues[runIndex - 1];
21.488 + if (oldRunAttributes != null) {
21.489 + newRunAttributes = (Vector) oldRunAttributes.clone();
21.490 + }
21.491 + if (oldRunAttributeValues != null) {
21.492 + newRunAttributeValues = (Vector) oldRunAttributeValues.clone();
21.493 + }
21.494 + }
21.495 +
21.496 + // now actually break up the run
21.497 + runCount++;
21.498 + for (int i = runCount - 1; i > runIndex; i--) {
21.499 + runStarts[i] = runStarts[i - 1];
21.500 + runAttributes[i] = runAttributes[i - 1];
21.501 + runAttributeValues[i] = runAttributeValues[i - 1];
21.502 + }
21.503 + runStarts[runIndex] = offset;
21.504 + runAttributes[runIndex] = newRunAttributes;
21.505 + runAttributeValues[runIndex] = newRunAttributeValues;
21.506 +
21.507 + return runIndex;
21.508 + }
21.509 +
21.510 + // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex
21.511 + private void addAttributeRunData(Attribute attribute, Object value,
21.512 + int beginRunIndex, int endRunIndex) {
21.513 +
21.514 + for (int i = beginRunIndex; i < endRunIndex; i++) {
21.515 + int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet
21.516 + if (runAttributes[i] == null) {
21.517 + Vector newRunAttributes = new Vector();
21.518 + Vector newRunAttributeValues = new Vector();
21.519 + runAttributes[i] = newRunAttributes;
21.520 + runAttributeValues[i] = newRunAttributeValues;
21.521 + } else {
21.522 + // check whether we have an entry already
21.523 + keyValueIndex = runAttributes[i].indexOf(attribute);
21.524 + }
21.525 +
21.526 + if (keyValueIndex == -1) {
21.527 + // create new entry
21.528 + int oldSize = runAttributes[i].size();
21.529 + runAttributes[i].addElement(attribute);
21.530 + try {
21.531 + runAttributeValues[i].addElement(value);
21.532 + }
21.533 + catch (Exception e) {
21.534 + runAttributes[i].setSize(oldSize);
21.535 + runAttributeValues[i].setSize(oldSize);
21.536 + }
21.537 + } else {
21.538 + // update existing entry
21.539 + runAttributeValues[i].set(keyValueIndex, value);
21.540 + }
21.541 + }
21.542 + }
21.543 +
21.544 + /**
21.545 + * Creates an AttributedCharacterIterator instance that provides access to the entire contents of
21.546 + * this string.
21.547 + *
21.548 + * @return An iterator providing access to the text and its attributes.
21.549 + */
21.550 + public AttributedCharacterIterator getIterator() {
21.551 + return getIterator(null, 0, length());
21.552 + }
21.553 +
21.554 + /**
21.555 + * Creates an AttributedCharacterIterator instance that provides access to
21.556 + * selected contents of this string.
21.557 + * Information about attributes not listed in attributes that the
21.558 + * implementor may have need not be made accessible through the iterator.
21.559 + * If the list is null, all available attribute information should be made
21.560 + * accessible.
21.561 + *
21.562 + * @param attributes a list of attributes that the client is interested in
21.563 + * @return an iterator providing access to the entire text and its selected attributes
21.564 + */
21.565 + public AttributedCharacterIterator getIterator(Attribute[] attributes) {
21.566 + return getIterator(attributes, 0, length());
21.567 + }
21.568 +
21.569 + /**
21.570 + * Creates an AttributedCharacterIterator instance that provides access to
21.571 + * selected contents of this string.
21.572 + * Information about attributes not listed in attributes that the
21.573 + * implementor may have need not be made accessible through the iterator.
21.574 + * If the list is null, all available attribute information should be made
21.575 + * accessible.
21.576 + *
21.577 + * @param attributes a list of attributes that the client is interested in
21.578 + * @param beginIndex the index of the first character
21.579 + * @param endIndex the index of the character following the last character
21.580 + * @return an iterator providing access to the text and its attributes
21.581 + * @exception IllegalArgumentException if beginIndex is less then 0,
21.582 + * endIndex is greater than the length of the string, or beginIndex is
21.583 + * greater than endIndex.
21.584 + */
21.585 + public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
21.586 + return new AttributedStringIterator(attributes, beginIndex, endIndex);
21.587 + }
21.588 +
21.589 + // all (with the exception of length) reading operations are private,
21.590 + // since AttributedString instances are accessed through iterators.
21.591 +
21.592 + // length is package private so that CharacterIteratorFieldDelegate can
21.593 + // access it without creating an AttributedCharacterIterator.
21.594 + int length() {
21.595 + return text.length();
21.596 + }
21.597 +
21.598 + private char charAt(int index) {
21.599 + return text.charAt(index);
21.600 + }
21.601 +
21.602 + private synchronized Object getAttribute(Attribute attribute, int runIndex) {
21.603 + Vector currentRunAttributes = runAttributes[runIndex];
21.604 + Vector currentRunAttributeValues = runAttributeValues[runIndex];
21.605 + if (currentRunAttributes == null) {
21.606 + return null;
21.607 + }
21.608 + int attributeIndex = currentRunAttributes.indexOf(attribute);
21.609 + if (attributeIndex != -1) {
21.610 + return currentRunAttributeValues.elementAt(attributeIndex);
21.611 + }
21.612 + else {
21.613 + return null;
21.614 + }
21.615 + }
21.616 +
21.617 + // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
21.618 + private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
21.619 + Object value = getAttribute(attribute, runIndex);
21.620 + if (value instanceof Annotation) {
21.621 + // need to check whether the annotation's range extends outside the iterator's range
21.622 + if (beginIndex > 0) {
21.623 + int currIndex = runIndex;
21.624 + int runStart = runStarts[currIndex];
21.625 + while (runStart >= beginIndex &&
21.626 + valuesMatch(value, getAttribute(attribute, currIndex - 1))) {
21.627 + currIndex--;
21.628 + runStart = runStarts[currIndex];
21.629 + }
21.630 + if (runStart < beginIndex) {
21.631 + // annotation's range starts before iterator's range
21.632 + return null;
21.633 + }
21.634 + }
21.635 + int textLength = length();
21.636 + if (endIndex < textLength) {
21.637 + int currIndex = runIndex;
21.638 + int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
21.639 + while (runLimit <= endIndex &&
21.640 + valuesMatch(value, getAttribute(attribute, currIndex + 1))) {
21.641 + currIndex++;
21.642 + runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
21.643 + }
21.644 + if (runLimit > endIndex) {
21.645 + // annotation's range ends after iterator's range
21.646 + return null;
21.647 + }
21.648 + }
21.649 + // annotation's range is subrange of iterator's range,
21.650 + // so we can return the value
21.651 + }
21.652 + return value;
21.653 + }
21.654 +
21.655 + // returns whether all specified attributes have equal values in the runs with the given indices
21.656 + private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) {
21.657 + Iterator iterator = attributes.iterator();
21.658 + while (iterator.hasNext()) {
21.659 + Attribute key = (Attribute) iterator.next();
21.660 + if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) {
21.661 + return false;
21.662 + }
21.663 + }
21.664 + return true;
21.665 + }
21.666 +
21.667 + // returns whether the two objects are either both null or equal
21.668 + private final static boolean valuesMatch(Object value1, Object value2) {
21.669 + if (value1 == null) {
21.670 + return value2 == null;
21.671 + } else {
21.672 + return value1.equals(value2);
21.673 + }
21.674 + }
21.675 +
21.676 + /**
21.677 + * Appends the contents of the CharacterIterator iterator into the
21.678 + * StringBuffer buf.
21.679 + */
21.680 + private final void appendContents(StringBuffer buf,
21.681 + CharacterIterator iterator) {
21.682 + int index = iterator.getBeginIndex();
21.683 + int end = iterator.getEndIndex();
21.684 +
21.685 + while (index < end) {
21.686 + iterator.setIndex(index++);
21.687 + buf.append(iterator.current());
21.688 + }
21.689 + }
21.690 +
21.691 + /**
21.692 + * Sets the attributes for the range from offset to the next run break
21.693 + * (typically the end of the text) to the ones specified in attrs.
21.694 + * This is only meant to be called from the constructor!
21.695 + */
21.696 + private void setAttributes(Map attrs, int offset) {
21.697 + if (runCount == 0) {
21.698 + createRunAttributeDataVectors();
21.699 + }
21.700 +
21.701 + int index = ensureRunBreak(offset, false);
21.702 + int size;
21.703 +
21.704 + if (attrs != null && (size = attrs.size()) > 0) {
21.705 + Vector runAttrs = new Vector(size);
21.706 + Vector runValues = new Vector(size);
21.707 + Iterator iterator = attrs.entrySet().iterator();
21.708 +
21.709 + while (iterator.hasNext()) {
21.710 + Map.Entry entry = (Map.Entry)iterator.next();
21.711 +
21.712 + runAttrs.add(entry.getKey());
21.713 + runValues.add(entry.getValue());
21.714 + }
21.715 + runAttributes[index] = runAttrs;
21.716 + runAttributeValues[index] = runValues;
21.717 + }
21.718 + }
21.719 +
21.720 + /**
21.721 + * Returns true if the attributes specified in last and attrs differ.
21.722 + */
21.723 + private static boolean mapsDiffer(Map last, Map attrs) {
21.724 + if (last == null) {
21.725 + return (attrs != null && attrs.size() > 0);
21.726 + }
21.727 + return (!last.equals(attrs));
21.728 + }
21.729 +
21.730 +
21.731 + // the iterator class associated with this string class
21.732 +
21.733 + final private class AttributedStringIterator implements AttributedCharacterIterator {
21.734 +
21.735 + // note on synchronization:
21.736 + // we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
21.737 + // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
21.738 +
21.739 + // start and end index for our iteration
21.740 + private int beginIndex;
21.741 + private int endIndex;
21.742 +
21.743 + // attributes that our client is interested in
21.744 + private Attribute[] relevantAttributes;
21.745 +
21.746 + // the current index for our iteration
21.747 + // invariant: beginIndex <= currentIndex <= endIndex
21.748 + private int currentIndex;
21.749 +
21.750 + // information about the run that includes currentIndex
21.751 + private int currentRunIndex;
21.752 + private int currentRunStart;
21.753 + private int currentRunLimit;
21.754 +
21.755 + // constructor
21.756 + AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) {
21.757 +
21.758 + if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
21.759 + throw new IllegalArgumentException("Invalid substring range");
21.760 + }
21.761 +
21.762 + this.beginIndex = beginIndex;
21.763 + this.endIndex = endIndex;
21.764 + this.currentIndex = beginIndex;
21.765 + updateRunInfo();
21.766 + if (attributes != null) {
21.767 + relevantAttributes = (Attribute[]) attributes.clone();
21.768 + }
21.769 + }
21.770 +
21.771 + // Object methods. See documentation in that class.
21.772 +
21.773 + public boolean equals(Object obj) {
21.774 + if (this == obj) {
21.775 + return true;
21.776 + }
21.777 + if (!(obj instanceof AttributedStringIterator)) {
21.778 + return false;
21.779 + }
21.780 +
21.781 + AttributedStringIterator that = (AttributedStringIterator) obj;
21.782 +
21.783 + if (AttributedString.this != that.getString())
21.784 + return false;
21.785 + if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
21.786 + return false;
21.787 + return true;
21.788 + }
21.789 +
21.790 + public int hashCode() {
21.791 + return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex;
21.792 + }
21.793 +
21.794 + public Object clone() {
21.795 + try {
21.796 + AttributedStringIterator other = (AttributedStringIterator) super.clone();
21.797 + return other;
21.798 + }
21.799 + catch (CloneNotSupportedException e) {
21.800 + throw new InternalError();
21.801 + }
21.802 + }
21.803 +
21.804 + // CharacterIterator methods. See documentation in that interface.
21.805 +
21.806 + public char first() {
21.807 + return internalSetIndex(beginIndex);
21.808 + }
21.809 +
21.810 + public char last() {
21.811 + if (endIndex == beginIndex) {
21.812 + return internalSetIndex(endIndex);
21.813 + } else {
21.814 + return internalSetIndex(endIndex - 1);
21.815 + }
21.816 + }
21.817 +
21.818 + public char current() {
21.819 + if (currentIndex == endIndex) {
21.820 + return DONE;
21.821 + } else {
21.822 + return charAt(currentIndex);
21.823 + }
21.824 + }
21.825 +
21.826 + public char next() {
21.827 + if (currentIndex < endIndex) {
21.828 + return internalSetIndex(currentIndex + 1);
21.829 + }
21.830 + else {
21.831 + return DONE;
21.832 + }
21.833 + }
21.834 +
21.835 + public char previous() {
21.836 + if (currentIndex > beginIndex) {
21.837 + return internalSetIndex(currentIndex - 1);
21.838 + }
21.839 + else {
21.840 + return DONE;
21.841 + }
21.842 + }
21.843 +
21.844 + public char setIndex(int position) {
21.845 + if (position < beginIndex || position > endIndex)
21.846 + throw new IllegalArgumentException("Invalid index");
21.847 + return internalSetIndex(position);
21.848 + }
21.849 +
21.850 + public int getBeginIndex() {
21.851 + return beginIndex;
21.852 + }
21.853 +
21.854 + public int getEndIndex() {
21.855 + return endIndex;
21.856 + }
21.857 +
21.858 + public int getIndex() {
21.859 + return currentIndex;
21.860 + }
21.861 +
21.862 + // AttributedCharacterIterator methods. See documentation in that interface.
21.863 +
21.864 + public int getRunStart() {
21.865 + return currentRunStart;
21.866 + }
21.867 +
21.868 + public int getRunStart(Attribute attribute) {
21.869 + if (currentRunStart == beginIndex || currentRunIndex == -1) {
21.870 + return currentRunStart;
21.871 + } else {
21.872 + Object value = getAttribute(attribute);
21.873 + int runStart = currentRunStart;
21.874 + int runIndex = currentRunIndex;
21.875 + while (runStart > beginIndex &&
21.876 + valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) {
21.877 + runIndex--;
21.878 + runStart = runStarts[runIndex];
21.879 + }
21.880 + if (runStart < beginIndex) {
21.881 + runStart = beginIndex;
21.882 + }
21.883 + return runStart;
21.884 + }
21.885 + }
21.886 +
21.887 + public int getRunStart(Set<? extends Attribute> attributes) {
21.888 + if (currentRunStart == beginIndex || currentRunIndex == -1) {
21.889 + return currentRunStart;
21.890 + } else {
21.891 + int runStart = currentRunStart;
21.892 + int runIndex = currentRunIndex;
21.893 + while (runStart > beginIndex &&
21.894 + AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) {
21.895 + runIndex--;
21.896 + runStart = runStarts[runIndex];
21.897 + }
21.898 + if (runStart < beginIndex) {
21.899 + runStart = beginIndex;
21.900 + }
21.901 + return runStart;
21.902 + }
21.903 + }
21.904 +
21.905 + public int getRunLimit() {
21.906 + return currentRunLimit;
21.907 + }
21.908 +
21.909 + public int getRunLimit(Attribute attribute) {
21.910 + if (currentRunLimit == endIndex || currentRunIndex == -1) {
21.911 + return currentRunLimit;
21.912 + } else {
21.913 + Object value = getAttribute(attribute);
21.914 + int runLimit = currentRunLimit;
21.915 + int runIndex = currentRunIndex;
21.916 + while (runLimit < endIndex &&
21.917 + valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) {
21.918 + runIndex++;
21.919 + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
21.920 + }
21.921 + if (runLimit > endIndex) {
21.922 + runLimit = endIndex;
21.923 + }
21.924 + return runLimit;
21.925 + }
21.926 + }
21.927 +
21.928 + public int getRunLimit(Set<? extends Attribute> attributes) {
21.929 + if (currentRunLimit == endIndex || currentRunIndex == -1) {
21.930 + return currentRunLimit;
21.931 + } else {
21.932 + int runLimit = currentRunLimit;
21.933 + int runIndex = currentRunIndex;
21.934 + while (runLimit < endIndex &&
21.935 + AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) {
21.936 + runIndex++;
21.937 + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
21.938 + }
21.939 + if (runLimit > endIndex) {
21.940 + runLimit = endIndex;
21.941 + }
21.942 + return runLimit;
21.943 + }
21.944 + }
21.945 +
21.946 + public Map<Attribute,Object> getAttributes() {
21.947 + if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) {
21.948 + // ??? would be nice to return null, but current spec doesn't allow it
21.949 + // returning Hashtable saves AttributeMap from dealing with emptiness
21.950 + return new Hashtable();
21.951 + }
21.952 + return new AttributeMap(currentRunIndex, beginIndex, endIndex);
21.953 + }
21.954 +
21.955 + public Set<Attribute> getAllAttributeKeys() {
21.956 + // ??? This should screen out attribute keys that aren't relevant to the client
21.957 + if (runAttributes == null) {
21.958 + // ??? would be nice to return null, but current spec doesn't allow it
21.959 + // returning HashSet saves us from dealing with emptiness
21.960 + return new HashSet();
21.961 + }
21.962 + synchronized (AttributedString.this) {
21.963 + // ??? should try to create this only once, then update if necessary,
21.964 + // and give callers read-only view
21.965 + Set keys = new HashSet();
21.966 + int i = 0;
21.967 + while (i < runCount) {
21.968 + if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) {
21.969 + Vector currentRunAttributes = runAttributes[i];
21.970 + if (currentRunAttributes != null) {
21.971 + int j = currentRunAttributes.size();
21.972 + while (j-- > 0) {
21.973 + keys.add(currentRunAttributes.get(j));
21.974 + }
21.975 + }
21.976 + }
21.977 + i++;
21.978 + }
21.979 + return keys;
21.980 + }
21.981 + }
21.982 +
21.983 + public Object getAttribute(Attribute attribute) {
21.984 + int runIndex = currentRunIndex;
21.985 + if (runIndex < 0) {
21.986 + return null;
21.987 + }
21.988 + return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex);
21.989 + }
21.990 +
21.991 + // internally used methods
21.992 +
21.993 + private AttributedString getString() {
21.994 + return AttributedString.this;
21.995 + }
21.996 +
21.997 + // set the current index, update information about the current run if necessary,
21.998 + // return the character at the current index
21.999 + private char internalSetIndex(int position) {
21.1000 + currentIndex = position;
21.1001 + if (position < currentRunStart || position >= currentRunLimit) {
21.1002 + updateRunInfo();
21.1003 + }
21.1004 + if (currentIndex == endIndex) {
21.1005 + return DONE;
21.1006 + } else {
21.1007 + return charAt(position);
21.1008 + }
21.1009 + }
21.1010 +
21.1011 + // update the information about the current run
21.1012 + private void updateRunInfo() {
21.1013 + if (currentIndex == endIndex) {
21.1014 + currentRunStart = currentRunLimit = endIndex;
21.1015 + currentRunIndex = -1;
21.1016 + } else {
21.1017 + synchronized (AttributedString.this) {
21.1018 + int runIndex = -1;
21.1019 + while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex)
21.1020 + runIndex++;
21.1021 + currentRunIndex = runIndex;
21.1022 + if (runIndex >= 0) {
21.1023 + currentRunStart = runStarts[runIndex];
21.1024 + if (currentRunStart < beginIndex)
21.1025 + currentRunStart = beginIndex;
21.1026 + }
21.1027 + else {
21.1028 + currentRunStart = beginIndex;
21.1029 + }
21.1030 + if (runIndex < runCount - 1) {
21.1031 + currentRunLimit = runStarts[runIndex + 1];
21.1032 + if (currentRunLimit > endIndex)
21.1033 + currentRunLimit = endIndex;
21.1034 + }
21.1035 + else {
21.1036 + currentRunLimit = endIndex;
21.1037 + }
21.1038 + }
21.1039 + }
21.1040 + }
21.1041 +
21.1042 + }
21.1043 +
21.1044 + // the map class associated with this string class, giving access to the attributes of one run
21.1045 +
21.1046 + final private class AttributeMap extends AbstractMap<Attribute,Object> {
21.1047 +
21.1048 + int runIndex;
21.1049 + int beginIndex;
21.1050 + int endIndex;
21.1051 +
21.1052 + AttributeMap(int runIndex, int beginIndex, int endIndex) {
21.1053 + this.runIndex = runIndex;
21.1054 + this.beginIndex = beginIndex;
21.1055 + this.endIndex = endIndex;
21.1056 + }
21.1057 +
21.1058 + public Set entrySet() {
21.1059 + HashSet set = new HashSet();
21.1060 + synchronized (AttributedString.this) {
21.1061 + int size = runAttributes[runIndex].size();
21.1062 + for (int i = 0; i < size; i++) {
21.1063 + Attribute key = (Attribute) runAttributes[runIndex].get(i);
21.1064 + Object value = runAttributeValues[runIndex].get(i);
21.1065 + if (value instanceof Annotation) {
21.1066 + value = AttributedString.this.getAttributeCheckRange(key,
21.1067 + runIndex, beginIndex, endIndex);
21.1068 + if (value == null) {
21.1069 + continue;
21.1070 + }
21.1071 + }
21.1072 + Map.Entry entry = new AttributeEntry(key, value);
21.1073 + set.add(entry);
21.1074 + }
21.1075 + }
21.1076 + return set;
21.1077 + }
21.1078 +
21.1079 + public Object get(Object key) {
21.1080 + return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
21.1081 + }
21.1082 + }
21.1083 +}
21.1084 +
21.1085 +class AttributeEntry implements Map.Entry {
21.1086 +
21.1087 + private Attribute key;
21.1088 + private Object value;
21.1089 +
21.1090 + AttributeEntry(Attribute key, Object value) {
21.1091 + this.key = key;
21.1092 + this.value = value;
21.1093 + }
21.1094 +
21.1095 + public boolean equals(Object o) {
21.1096 + if (!(o instanceof AttributeEntry)) {
21.1097 + return false;
21.1098 + }
21.1099 + AttributeEntry other = (AttributeEntry) o;
21.1100 + return other.key.equals(key) &&
21.1101 + (value == null ? other.value == null : other.value.equals(value));
21.1102 + }
21.1103 +
21.1104 + public Object getKey() {
21.1105 + return key;
21.1106 + }
21.1107 +
21.1108 + public Object getValue() {
21.1109 + return value;
21.1110 + }
21.1111 +
21.1112 + public Object setValue(Object newValue) {
21.1113 + throw new UnsupportedOperationException();
21.1114 + }
21.1115 +
21.1116 + public int hashCode() {
21.1117 + return key.hashCode() ^ (value==null ? 0 : value.hashCode());
21.1118 + }
21.1119 +
21.1120 + public String toString() {
21.1121 + return key.toString()+"="+value.toString();
21.1122 + }
21.1123 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/rt/emul/compact/src/main/java/java/text/CalendarBuilder.java Thu Oct 03 15:40:35 2013 +0200
22.3 @@ -0,0 +1,170 @@
22.4 +/*
22.5 + * Copyright (c) 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.util.Calendar;
22.32 +import static java.util.GregorianCalendar.*;
22.33 +
22.34 +/**
22.35 + * {@code CalendarBuilder} keeps field-value pairs for setting
22.36 + * the calendar fields of the given {@code Calendar}. It has the
22.37 + * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
22.38 + * support. Also {@code ISO_DAY_OF_WEEK} is used to specify
22.39 + * {@code DAY_OF_WEEK} in the ISO day of week numbering.
22.40 + *
22.41 + * <p>{@code CalendarBuilder} retains the semantic of the pseudo
22.42 + * timestamp for fields. {@code CalendarBuilder} uses a single
22.43 + * int array combining fields[] and stamp[] of {@code Calendar}.
22.44 + *
22.45 + * @author Masayoshi Okutsu
22.46 + */
22.47 +class CalendarBuilder {
22.48 + /*
22.49 + * Pseudo time stamp constants used in java.util.Calendar
22.50 + */
22.51 + private static final int UNSET = 0;
22.52 + private static final int COMPUTED = 1;
22.53 + private static final int MINIMUM_USER_STAMP = 2;
22.54 +
22.55 + private static final int MAX_FIELD = FIELD_COUNT + 1;
22.56 +
22.57 + public static final int WEEK_YEAR = FIELD_COUNT;
22.58 + public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
22.59 +
22.60 + // stamp[] (lower half) and field[] (upper half) combined
22.61 + private final int[] field;
22.62 + private int nextStamp;
22.63 + private int maxFieldIndex;
22.64 +
22.65 + CalendarBuilder() {
22.66 + field = new int[MAX_FIELD * 2];
22.67 + nextStamp = MINIMUM_USER_STAMP;
22.68 + maxFieldIndex = -1;
22.69 + }
22.70 +
22.71 + CalendarBuilder set(int index, int value) {
22.72 + if (index == ISO_DAY_OF_WEEK) {
22.73 + index = DAY_OF_WEEK;
22.74 + value = toCalendarDayOfWeek(value);
22.75 + }
22.76 + field[index] = nextStamp++;
22.77 + field[MAX_FIELD + index] = value;
22.78 + if (index > maxFieldIndex && index < FIELD_COUNT) {
22.79 + maxFieldIndex = index;
22.80 + }
22.81 + return this;
22.82 + }
22.83 +
22.84 + CalendarBuilder addYear(int value) {
22.85 + field[MAX_FIELD + YEAR] += value;
22.86 + field[MAX_FIELD + WEEK_YEAR] += value;
22.87 + return this;
22.88 + }
22.89 +
22.90 + boolean isSet(int index) {
22.91 + if (index == ISO_DAY_OF_WEEK) {
22.92 + index = DAY_OF_WEEK;
22.93 + }
22.94 + return field[index] > UNSET;
22.95 + }
22.96 +
22.97 + Calendar establish(Calendar cal) {
22.98 + boolean weekDate = isSet(WEEK_YEAR)
22.99 + && field[WEEK_YEAR] > field[YEAR];
22.100 + if (weekDate && !cal.isWeekDateSupported()) {
22.101 + // Use YEAR instead
22.102 + if (!isSet(YEAR)) {
22.103 + set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
22.104 + }
22.105 + weekDate = false;
22.106 + }
22.107 +
22.108 + cal.clear();
22.109 + // Set the fields from the min stamp to the max stamp so that
22.110 + // the field resolution works in the Calendar.
22.111 + for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
22.112 + for (int index = 0; index <= maxFieldIndex; index++) {
22.113 + if (field[index] == stamp) {
22.114 + cal.set(index, field[MAX_FIELD + index]);
22.115 + break;
22.116 + }
22.117 + }
22.118 + }
22.119 +
22.120 + if (weekDate) {
22.121 + int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
22.122 + int dayOfWeek = isSet(DAY_OF_WEEK) ?
22.123 + field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
22.124 + if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
22.125 + if (dayOfWeek >= 8) {
22.126 + dayOfWeek--;
22.127 + weekOfYear += dayOfWeek / 7;
22.128 + dayOfWeek = (dayOfWeek % 7) + 1;
22.129 + } else {
22.130 + while (dayOfWeek <= 0) {
22.131 + dayOfWeek += 7;
22.132 + weekOfYear--;
22.133 + }
22.134 + }
22.135 + dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
22.136 + }
22.137 + cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
22.138 + }
22.139 + return cal;
22.140 + }
22.141 +
22.142 + public String toString() {
22.143 + StringBuilder sb = new StringBuilder();
22.144 + sb.append("CalendarBuilder:[");
22.145 + for (int i = 0; i < field.length; i++) {
22.146 + if (isSet(i)) {
22.147 + sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
22.148 + }
22.149 + }
22.150 + int lastIndex = sb.length() - 1;
22.151 + if (sb.charAt(lastIndex) == ',') {
22.152 + sb.setLength(lastIndex);
22.153 + }
22.154 + sb.append(']');
22.155 + return sb.toString();
22.156 + }
22.157 +
22.158 + static int toISODayOfWeek(int calendarDayOfWeek) {
22.159 + return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
22.160 + }
22.161 +
22.162 + static int toCalendarDayOfWeek(int isoDayOfWeek) {
22.163 + if (!isValidDayOfWeek(isoDayOfWeek)) {
22.164 + // adjust later for lenient mode
22.165 + return isoDayOfWeek;
22.166 + }
22.167 + return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
22.168 + }
22.169 +
22.170 + static boolean isValidDayOfWeek(int dayOfWeek) {
22.171 + return dayOfWeek > 0 && dayOfWeek <= 7;
22.172 + }
22.173 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIterator.java Thu Oct 03 15:40:35 2013 +0200
23.3 @@ -0,0 +1,193 @@
23.4 +/*
23.5 + * Copyright (c) 1996, 2000, 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 +/*
23.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
23.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
23.32 + *
23.33 + * The original version of this source code and documentation
23.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
23.35 + * subsidiary of IBM. These materials are provided under terms
23.36 + * of a License Agreement between Taligent and Sun. This technology
23.37 + * is protected by multiple US and International patents.
23.38 + *
23.39 + * This notice and attribution to Taligent may not be removed.
23.40 + * Taligent is a registered trademark of Taligent, Inc.
23.41 + *
23.42 + */
23.43 +
23.44 +package java.text;
23.45 +
23.46 +
23.47 +/**
23.48 + * This interface defines a protocol for bidirectional iteration over text.
23.49 + * The iterator iterates over a bounded sequence of characters. Characters
23.50 + * are indexed with values beginning with the value returned by getBeginIndex() and
23.51 + * continuing through the value returned by getEndIndex()-1.
23.52 + * <p>
23.53 + * Iterators maintain a current character index, whose valid range is from
23.54 + * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
23.55 + * handling of zero-length text ranges and for historical reasons.
23.56 + * The current index can be retrieved by calling getIndex() and set directly
23.57 + * by calling setIndex(), first(), and last().
23.58 + * <p>
23.59 + * The methods previous() and next() are used for iteration. They return DONE if
23.60 + * they would move outside the range from getBeginIndex() to getEndIndex() -1,
23.61 + * signaling that the iterator has reached the end of the sequence. DONE is
23.62 + * also returned by other methods to indicate that the current index is
23.63 + * outside this range.
23.64 + *
23.65 + * <P>Examples:<P>
23.66 + *
23.67 + * Traverse the text from start to finish
23.68 + * <pre>
23.69 + * public void traverseForward(CharacterIterator iter) {
23.70 + * for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
23.71 + * processChar(c);
23.72 + * }
23.73 + * }
23.74 + * </pre>
23.75 + *
23.76 + * Traverse the text backwards, from end to start
23.77 + * <pre>
23.78 + * public void traverseBackward(CharacterIterator iter) {
23.79 + * for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
23.80 + * processChar(c);
23.81 + * }
23.82 + * }
23.83 + * </pre>
23.84 + *
23.85 + * Traverse both forward and backward from a given position in the text.
23.86 + * Calls to notBoundary() in this example represents some
23.87 + * additional stopping criteria.
23.88 + * <pre>
23.89 + * public void traverseOut(CharacterIterator iter, int pos) {
23.90 + * for (char c = iter.setIndex(pos);
23.91 + * c != CharacterIterator.DONE && notBoundary(c);
23.92 + * c = iter.next()) {
23.93 + * }
23.94 + * int end = iter.getIndex();
23.95 + * for (char c = iter.setIndex(pos);
23.96 + * c != CharacterIterator.DONE && notBoundary(c);
23.97 + * c = iter.previous()) {
23.98 + * }
23.99 + * int start = iter.getIndex();
23.100 + * processSection(start, end);
23.101 + * }
23.102 + * </pre>
23.103 + *
23.104 + * @see StringCharacterIterator
23.105 + * @see AttributedCharacterIterator
23.106 + */
23.107 +
23.108 +public interface CharacterIterator extends Cloneable
23.109 +{
23.110 +
23.111 + /**
23.112 + * Constant that is returned when the iterator has reached either the end
23.113 + * or the beginning of the text. The value is '\\uFFFF', the "not a
23.114 + * character" value which should not occur in any valid Unicode string.
23.115 + */
23.116 + public static final char DONE = '\uFFFF';
23.117 +
23.118 + /**
23.119 + * Sets the position to getBeginIndex() and returns the character at that
23.120 + * position.
23.121 + * @return the first character in the text, or DONE if the text is empty
23.122 + * @see #getBeginIndex()
23.123 + */
23.124 + public char first();
23.125 +
23.126 + /**
23.127 + * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
23.128 + * and returns the character at that position.
23.129 + * @return the last character in the text, or DONE if the text is empty
23.130 + * @see #getEndIndex()
23.131 + */
23.132 + public char last();
23.133 +
23.134 + /**
23.135 + * Gets the character at the current position (as returned by getIndex()).
23.136 + * @return the character at the current position or DONE if the current
23.137 + * position is off the end of the text.
23.138 + * @see #getIndex()
23.139 + */
23.140 + public char current();
23.141 +
23.142 + /**
23.143 + * Increments the iterator's index by one and returns the character
23.144 + * at the new index. If the resulting index is greater or equal
23.145 + * to getEndIndex(), the current index is reset to getEndIndex() and
23.146 + * a value of DONE is returned.
23.147 + * @return the character at the new position or DONE if the new
23.148 + * position is off the end of the text range.
23.149 + */
23.150 + public char next();
23.151 +
23.152 + /**
23.153 + * Decrements the iterator's index by one and returns the character
23.154 + * at the new index. If the current index is getBeginIndex(), the index
23.155 + * remains at getBeginIndex() and a value of DONE is returned.
23.156 + * @return the character at the new position or DONE if the current
23.157 + * position is equal to getBeginIndex().
23.158 + */
23.159 + public char previous();
23.160 +
23.161 + /**
23.162 + * Sets the position to the specified position in the text and returns that
23.163 + * character.
23.164 + * @param position the position within the text. Valid values range from
23.165 + * getBeginIndex() to getEndIndex(). An IllegalArgumentException is thrown
23.166 + * if an invalid value is supplied.
23.167 + * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
23.168 + */
23.169 + public char setIndex(int position);
23.170 +
23.171 + /**
23.172 + * Returns the start index of the text.
23.173 + * @return the index at which the text begins.
23.174 + */
23.175 + public int getBeginIndex();
23.176 +
23.177 + /**
23.178 + * Returns the end index of the text. This index is the index of the first
23.179 + * character following the end of the text.
23.180 + * @return the index after the last character in the text
23.181 + */
23.182 + public int getEndIndex();
23.183 +
23.184 + /**
23.185 + * Returns the current index.
23.186 + * @return the current index.
23.187 + */
23.188 + public int getIndex();
23.189 +
23.190 + /**
23.191 + * Create a copy of this iterator
23.192 + * @return A copy of this
23.193 + */
23.194 + public Object clone();
23.195 +
23.196 +}
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIteratorFieldDelegate.java Thu Oct 03 15:40:35 2013 +0200
24.3 @@ -0,0 +1,124 @@
24.4 +/*
24.5 + * Copyright (c) 2000, 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 +package java.text;
24.29 +
24.30 +import java.util.ArrayList;
24.31 +
24.32 +/**
24.33 + * CharacterIteratorFieldDelegate combines the notifications from a Format
24.34 + * into a resulting <code>AttributedCharacterIterator</code>. The resulting
24.35 + * <code>AttributedCharacterIterator</code> can be retrieved by way of
24.36 + * the <code>getIterator</code> method.
24.37 + *
24.38 + */
24.39 +class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
24.40 + /**
24.41 + * Array of AttributeStrings. Whenever <code>formatted</code> is invoked
24.42 + * for a region > size, a new instance of AttributedString is added to
24.43 + * attributedStrings. Subsequent invocations of <code>formatted</code>
24.44 + * for existing regions result in invoking addAttribute on the existing
24.45 + * AttributedStrings.
24.46 + */
24.47 + private ArrayList attributedStrings;
24.48 + /**
24.49 + * Running count of the number of characters that have
24.50 + * been encountered.
24.51 + */
24.52 + private int size;
24.53 +
24.54 +
24.55 + CharacterIteratorFieldDelegate() {
24.56 + attributedStrings = new ArrayList();
24.57 + }
24.58 +
24.59 + public void formatted(Format.Field attr, Object value, int start, int end,
24.60 + StringBuffer buffer) {
24.61 + if (start != end) {
24.62 + if (start < size) {
24.63 + // Adjust attributes of existing runs
24.64 + int index = size;
24.65 + int asIndex = attributedStrings.size() - 1;
24.66 +
24.67 + while (start < index) {
24.68 + AttributedString as = (AttributedString)attributedStrings.
24.69 + get(asIndex--);
24.70 + int newIndex = index - as.length();
24.71 + int aStart = Math.max(0, start - newIndex);
24.72 +
24.73 + as.addAttribute(attr, value, aStart, Math.min(
24.74 + end - start, as.length() - aStart) +
24.75 + aStart);
24.76 + index = newIndex;
24.77 + }
24.78 + }
24.79 + if (size < start) {
24.80 + // Pad attributes
24.81 + attributedStrings.add(new AttributedString(
24.82 + buffer.substring(size, start)));
24.83 + size = start;
24.84 + }
24.85 + if (size < end) {
24.86 + // Add new string
24.87 + int aStart = Math.max(start, size);
24.88 + AttributedString string = new AttributedString(
24.89 + buffer.substring(aStart, end));
24.90 +
24.91 + string.addAttribute(attr, value);
24.92 + attributedStrings.add(string);
24.93 + size = end;
24.94 + }
24.95 + }
24.96 + }
24.97 +
24.98 + public void formatted(int fieldID, Format.Field attr, Object value,
24.99 + int start, int end, StringBuffer buffer) {
24.100 + formatted(attr, value, start, end, buffer);
24.101 + }
24.102 +
24.103 + /**
24.104 + * Returns an <code>AttributedCharacterIterator</code> that can be used
24.105 + * to iterate over the resulting formatted String.
24.106 + *
24.107 + * @pararm string Result of formatting.
24.108 + */
24.109 + public AttributedCharacterIterator getIterator(String string) {
24.110 + // Add the last AttributedCharacterIterator if necessary
24.111 + // assert(size <= string.length());
24.112 + if (string.length() > size) {
24.113 + attributedStrings.add(new AttributedString(
24.114 + string.substring(size)));
24.115 + size = string.length();
24.116 + }
24.117 + int iCount = attributedStrings.size();
24.118 + AttributedCharacterIterator iterators[] = new
24.119 + AttributedCharacterIterator[iCount];
24.120 +
24.121 + for (int counter = 0; counter < iCount; counter++) {
24.122 + iterators[counter] = ((AttributedString)attributedStrings.
24.123 + get(counter)).getIterator();
24.124 + }
24.125 + return new AttributedString(iterators).getIterator();
24.126 + }
24.127 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/rt/emul/compact/src/main/java/java/text/ChoiceFormat.java Thu Oct 03 15:40:35 2013 +0200
25.3 @@ -0,0 +1,619 @@
25.4 +/*
25.5 + * Copyright (c) 1996, 2005, 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 is copyrighted
25.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
25.35 + * materials are provided under terms of a License Agreement between Taligent
25.36 + * and Sun. This technology is protected by multiple US and International
25.37 + * patents. This notice and attribution to Taligent may not be removed.
25.38 + * Taligent is a registered trademark of Taligent, Inc.
25.39 + *
25.40 + */
25.41 +
25.42 +package java.text;
25.43 +
25.44 +import java.io.InvalidObjectException;
25.45 +import java.io.IOException;
25.46 +import java.io.ObjectInputStream;
25.47 +import java.util.Arrays;
25.48 +
25.49 +/**
25.50 + * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
25.51 + * It is generally used in a <code>MessageFormat</code> for handling plurals.
25.52 + * The choice is specified with an ascending list of doubles, where each item
25.53 + * specifies a half-open interval up to the next item:
25.54 + * <blockquote>
25.55 + * <pre>
25.56 + * X matches j if and only if limit[j] <= X < limit[j+1]
25.57 + * </pre>
25.58 + * </blockquote>
25.59 + * If there is no match, then either the first or last index is used, depending
25.60 + * on whether the number (X) is too low or too high. If the limit array is not
25.61 + * in ascending order, the results of formatting will be incorrect. ChoiceFormat
25.62 + * also accepts <code>\u221E</code> as equivalent to infinity(INF).
25.63 + *
25.64 + * <p>
25.65 + * <strong>Note:</strong>
25.66 + * <code>ChoiceFormat</code> differs from the other <code>Format</code>
25.67 + * classes in that you create a <code>ChoiceFormat</code> object with a
25.68 + * constructor (not with a <code>getInstance</code> style factory
25.69 + * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
25.70 + * doesn't require any complex setup for a given locale. In fact,
25.71 + * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
25.72 + *
25.73 + * <p>
25.74 + * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
25.75 + * and an array of limits. The length of these arrays must be the same.
25.76 + * For example,
25.77 + * <ul>
25.78 + * <li>
25.79 + * <em>limits</em> = {1,2,3,4,5,6,7}<br>
25.80 + * <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
25.81 + * <li>
25.82 + * <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
25.83 + * <em>formats</em> = {"no files", "one file", "many files"}<br>
25.84 + * (<code>nextDouble</code> can be used to get the next higher double, to
25.85 + * make the half-open interval.)
25.86 + * </ul>
25.87 + *
25.88 + * <p>
25.89 + * Here is a simple example that shows formatting and parsing:
25.90 + * <blockquote>
25.91 + * <pre>
25.92 + * double[] limits = {1,2,3,4,5,6,7};
25.93 + * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
25.94 + * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
25.95 + * ParsePosition status = new ParsePosition(0);
25.96 + * for (double i = 0.0; i <= 8.0; ++i) {
25.97 + * status.setIndex(0);
25.98 + * System.out.println(i + " -> " + form.format(i) + " -> "
25.99 + * + form.parse(form.format(i),status));
25.100 + * }
25.101 + * </pre>
25.102 + * </blockquote>
25.103 + * Here is a more complex example, with a pattern format:
25.104 + * <blockquote>
25.105 + * <pre>
25.106 + * double[] filelimits = {0,1,2};
25.107 + * String[] filepart = {"are no files","is one file","are {2} files"};
25.108 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
25.109 + * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
25.110 + * MessageFormat pattform = new MessageFormat("There {0} on {1}");
25.111 + * pattform.setFormats(testFormats);
25.112 + * Object[] testArgs = {null, "ADisk", null};
25.113 + * for (int i = 0; i < 4; ++i) {
25.114 + * testArgs[0] = new Integer(i);
25.115 + * testArgs[2] = testArgs[0];
25.116 + * System.out.println(pattform.format(testArgs));
25.117 + * }
25.118 + * </pre>
25.119 + * </blockquote>
25.120 + * <p>
25.121 + * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
25.122 + * For example:
25.123 + * <blockquote>
25.124 + * <pre>
25.125 + * ChoiceFormat fmt = new ChoiceFormat(
25.126 + * "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
25.127 + * System.out.println("Formatter Pattern : " + fmt.toPattern());
25.128 + *
25.129 + * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
25.130 + * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
25.131 + * System.out.println("Format with 0 : " + fmt.format(0));
25.132 + * System.out.println("Format with 0.9 : " + fmt.format(0.9));
25.133 + * System.out.println("Format with 1.0 : " + fmt.format(1));
25.134 + * System.out.println("Format with 1.5 : " + fmt.format(1.5));
25.135 + * System.out.println("Format with 2 : " + fmt.format(2));
25.136 + * System.out.println("Format with 2.1 : " + fmt.format(2.1));
25.137 + * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
25.138 + * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
25.139 + * </pre>
25.140 + * </blockquote>
25.141 + * And the output result would be like the following:
25.142 + * <blockquote>
25.143 + * <pre>
25.144 + * Format with -INF : is negative
25.145 + * Format with -1.0 : is negative
25.146 + * Format with 0 : is zero or fraction
25.147 + * Format with 0.9 : is zero or fraction
25.148 + * Format with 1.0 : is one
25.149 + * Format with 1.5 : is 1+
25.150 + * Format with 2 : is two
25.151 + * Format with 2.1 : is more than 2.
25.152 + * Format with NaN : is negative
25.153 + * Format with +INF : is more than 2.
25.154 + * </pre>
25.155 + * </blockquote>
25.156 + *
25.157 + * <h4><a name="synchronization">Synchronization</a></h4>
25.158 + *
25.159 + * <p>
25.160 + * Choice formats are not synchronized.
25.161 + * It is recommended to create separate format instances for each thread.
25.162 + * If multiple threads access a format concurrently, it must be synchronized
25.163 + * externally.
25.164 + *
25.165 + *
25.166 + * @see DecimalFormat
25.167 + * @see MessageFormat
25.168 + * @author Mark Davis
25.169 + */
25.170 +public class ChoiceFormat extends NumberFormat {
25.171 +
25.172 + // Proclaim serial compatibility with 1.1 FCS
25.173 + private static final long serialVersionUID = 1795184449645032964L;
25.174 +
25.175 + /**
25.176 + * Sets the pattern.
25.177 + * @param newPattern See the class description.
25.178 + */
25.179 + public void applyPattern(String newPattern) {
25.180 + StringBuffer[] segments = new StringBuffer[2];
25.181 + for (int i = 0; i < segments.length; ++i) {
25.182 + segments[i] = new StringBuffer();
25.183 + }
25.184 + double[] newChoiceLimits = new double[30];
25.185 + String[] newChoiceFormats = new String[30];
25.186 + int count = 0;
25.187 + int part = 0;
25.188 + double startValue = 0;
25.189 + double oldStartValue = Double.NaN;
25.190 + boolean inQuote = false;
25.191 + for (int i = 0; i < newPattern.length(); ++i) {
25.192 + char ch = newPattern.charAt(i);
25.193 + if (ch=='\'') {
25.194 + // Check for "''" indicating a literal quote
25.195 + if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
25.196 + segments[part].append(ch);
25.197 + ++i;
25.198 + } else {
25.199 + inQuote = !inQuote;
25.200 + }
25.201 + } else if (inQuote) {
25.202 + segments[part].append(ch);
25.203 + } else if (ch == '<' || ch == '#' || ch == '\u2264') {
25.204 + if (segments[0].length() == 0) {
25.205 + throw new IllegalArgumentException();
25.206 + }
25.207 + try {
25.208 + String tempBuffer = segments[0].toString();
25.209 + if (tempBuffer.equals("\u221E")) {
25.210 + startValue = Double.POSITIVE_INFINITY;
25.211 + } else if (tempBuffer.equals("-\u221E")) {
25.212 + startValue = Double.NEGATIVE_INFINITY;
25.213 + } else {
25.214 + startValue = Double.valueOf(segments[0].toString()).doubleValue();
25.215 + }
25.216 + } catch (Exception e) {
25.217 + throw new IllegalArgumentException();
25.218 + }
25.219 + if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
25.220 + startValue != Double.NEGATIVE_INFINITY) {
25.221 + startValue = nextDouble(startValue);
25.222 + }
25.223 + if (startValue <= oldStartValue) {
25.224 + throw new IllegalArgumentException();
25.225 + }
25.226 + segments[0].setLength(0);
25.227 + part = 1;
25.228 + } else if (ch == '|') {
25.229 + if (count == newChoiceLimits.length) {
25.230 + newChoiceLimits = doubleArraySize(newChoiceLimits);
25.231 + newChoiceFormats = doubleArraySize(newChoiceFormats);
25.232 + }
25.233 + newChoiceLimits[count] = startValue;
25.234 + newChoiceFormats[count] = segments[1].toString();
25.235 + ++count;
25.236 + oldStartValue = startValue;
25.237 + segments[1].setLength(0);
25.238 + part = 0;
25.239 + } else {
25.240 + segments[part].append(ch);
25.241 + }
25.242 + }
25.243 + // clean up last one
25.244 + if (part == 1) {
25.245 + if (count == newChoiceLimits.length) {
25.246 + newChoiceLimits = doubleArraySize(newChoiceLimits);
25.247 + newChoiceFormats = doubleArraySize(newChoiceFormats);
25.248 + }
25.249 + newChoiceLimits[count] = startValue;
25.250 + newChoiceFormats[count] = segments[1].toString();
25.251 + ++count;
25.252 + }
25.253 + choiceLimits = new double[count];
25.254 + System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
25.255 + choiceFormats = new String[count];
25.256 + System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
25.257 + }
25.258 +
25.259 + /**
25.260 + * Gets the pattern.
25.261 + */
25.262 + public String toPattern() {
25.263 + StringBuffer result = new StringBuffer();
25.264 + for (int i = 0; i < choiceLimits.length; ++i) {
25.265 + if (i != 0) {
25.266 + result.append('|');
25.267 + }
25.268 + // choose based upon which has less precision
25.269 + // approximate that by choosing the closest one to an integer.
25.270 + // could do better, but it's not worth it.
25.271 + double less = previousDouble(choiceLimits[i]);
25.272 + double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
25.273 + double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
25.274 +
25.275 + if (tryLessOrEqual < tryLess) {
25.276 + result.append(""+choiceLimits[i]);
25.277 + result.append('#');
25.278 + } else {
25.279 + if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
25.280 + result.append("\u221E");
25.281 + } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
25.282 + result.append("-\u221E");
25.283 + } else {
25.284 + result.append(""+less);
25.285 + }
25.286 + result.append('<');
25.287 + }
25.288 + // Append choiceFormats[i], using quotes if there are special characters.
25.289 + // Single quotes themselves must be escaped in either case.
25.290 + String text = choiceFormats[i];
25.291 + boolean needQuote = text.indexOf('<') >= 0
25.292 + || text.indexOf('#') >= 0
25.293 + || text.indexOf('\u2264') >= 0
25.294 + || text.indexOf('|') >= 0;
25.295 + if (needQuote) result.append('\'');
25.296 + if (text.indexOf('\'') < 0) result.append(text);
25.297 + else {
25.298 + for (int j=0; j<text.length(); ++j) {
25.299 + char c = text.charAt(j);
25.300 + result.append(c);
25.301 + if (c == '\'') result.append(c);
25.302 + }
25.303 + }
25.304 + if (needQuote) result.append('\'');
25.305 + }
25.306 + return result.toString();
25.307 + }
25.308 +
25.309 + /**
25.310 + * Constructs with limits and corresponding formats based on the pattern.
25.311 + * @see #applyPattern
25.312 + */
25.313 + public ChoiceFormat(String newPattern) {
25.314 + applyPattern(newPattern);
25.315 + }
25.316 +
25.317 + /**
25.318 + * Constructs with the limits and the corresponding formats.
25.319 + * @see #setChoices
25.320 + */
25.321 + public ChoiceFormat(double[] limits, String[] formats) {
25.322 + setChoices(limits, formats);
25.323 + }
25.324 +
25.325 + /**
25.326 + * Set the choices to be used in formatting.
25.327 + * @param limits contains the top value that you want
25.328 + * parsed with that format,and should be in ascending sorted order. When
25.329 + * formatting X, the choice will be the i, where
25.330 + * limit[i] <= X < limit[i+1].
25.331 + * If the limit array is not in ascending order, the results of formatting
25.332 + * will be incorrect.
25.333 + * @param formats are the formats you want to use for each limit.
25.334 + * They can be either Format objects or Strings.
25.335 + * When formatting with object Y,
25.336 + * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
25.337 + * is called. Otherwise Y.toString() is called.
25.338 + */
25.339 + public void setChoices(double[] limits, String formats[]) {
25.340 + if (limits.length != formats.length) {
25.341 + throw new IllegalArgumentException(
25.342 + "Array and limit arrays must be of the same length.");
25.343 + }
25.344 + choiceLimits = limits;
25.345 + choiceFormats = formats;
25.346 + }
25.347 +
25.348 + /**
25.349 + * Get the limits passed in the constructor.
25.350 + * @return the limits.
25.351 + */
25.352 + public double[] getLimits() {
25.353 + return choiceLimits;
25.354 + }
25.355 +
25.356 + /**
25.357 + * Get the formats passed in the constructor.
25.358 + * @return the formats.
25.359 + */
25.360 + public Object[] getFormats() {
25.361 + return choiceFormats;
25.362 + }
25.363 +
25.364 + // Overrides
25.365 +
25.366 + /**
25.367 + * Specialization of format. This method really calls
25.368 + * <code>format(double, StringBuffer, FieldPosition)</code>
25.369 + * thus the range of longs that are supported is only equal to
25.370 + * the range that can be stored by double. This will never be
25.371 + * a practical limitation.
25.372 + */
25.373 + public StringBuffer format(long number, StringBuffer toAppendTo,
25.374 + FieldPosition status) {
25.375 + return format((double)number, toAppendTo, status);
25.376 + }
25.377 +
25.378 + /**
25.379 + * Returns pattern with formatted double.
25.380 + * @param number number to be formatted & substituted.
25.381 + * @param toAppendTo where text is appended.
25.382 + * @param status ignore no useful status is returned.
25.383 + */
25.384 + public StringBuffer format(double number, StringBuffer toAppendTo,
25.385 + FieldPosition status) {
25.386 + // find the number
25.387 + int i;
25.388 + for (i = 0; i < choiceLimits.length; ++i) {
25.389 + if (!(number >= choiceLimits[i])) {
25.390 + // same as number < choiceLimits, except catchs NaN
25.391 + break;
25.392 + }
25.393 + }
25.394 + --i;
25.395 + if (i < 0) i = 0;
25.396 + // return either a formatted number, or a string
25.397 + return toAppendTo.append(choiceFormats[i]);
25.398 + }
25.399 +
25.400 + /**
25.401 + * Parses a Number from the input text.
25.402 + * @param text the source text.
25.403 + * @param status an input-output parameter. On input, the
25.404 + * status.index field indicates the first character of the
25.405 + * source text that should be parsed. On exit, if no error
25.406 + * occured, status.index is set to the first unparsed character
25.407 + * in the source text. On exit, if an error did occur,
25.408 + * status.index is unchanged and status.errorIndex is set to the
25.409 + * first index of the character that caused the parse to fail.
25.410 + * @return A Number representing the value of the number parsed.
25.411 + */
25.412 + public Number parse(String text, ParsePosition status) {
25.413 + // find the best number (defined as the one with the longest parse)
25.414 + int start = status.index;
25.415 + int furthest = start;
25.416 + double bestNumber = Double.NaN;
25.417 + double tempNumber = 0.0;
25.418 + for (int i = 0; i < choiceFormats.length; ++i) {
25.419 + String tempString = choiceFormats[i];
25.420 + if (text.regionMatches(start, tempString, 0, tempString.length())) {
25.421 + status.index = start + tempString.length();
25.422 + tempNumber = choiceLimits[i];
25.423 + if (status.index > furthest) {
25.424 + furthest = status.index;
25.425 + bestNumber = tempNumber;
25.426 + if (furthest == text.length()) break;
25.427 + }
25.428 + }
25.429 + }
25.430 + status.index = furthest;
25.431 + if (status.index == start) {
25.432 + status.errorIndex = furthest;
25.433 + }
25.434 + return new Double(bestNumber);
25.435 + }
25.436 +
25.437 + /**
25.438 + * Finds the least double greater than d.
25.439 + * If NaN, returns same value.
25.440 + * <p>Used to make half-open intervals.
25.441 + * @see #previousDouble
25.442 + */
25.443 + public static final double nextDouble (double d) {
25.444 + return nextDouble(d,true);
25.445 + }
25.446 +
25.447 + /**
25.448 + * Finds the greatest double less than d.
25.449 + * If NaN, returns same value.
25.450 + * @see #nextDouble
25.451 + */
25.452 + public static final double previousDouble (double d) {
25.453 + return nextDouble(d,false);
25.454 + }
25.455 +
25.456 + /**
25.457 + * Overrides Cloneable
25.458 + */
25.459 + public Object clone()
25.460 + {
25.461 + ChoiceFormat other = (ChoiceFormat) super.clone();
25.462 + // for primitives or immutables, shallow clone is enough
25.463 + other.choiceLimits = (double[]) choiceLimits.clone();
25.464 + other.choiceFormats = (String[]) choiceFormats.clone();
25.465 + return other;
25.466 + }
25.467 +
25.468 + /**
25.469 + * Generates a hash code for the message format object.
25.470 + */
25.471 + public int hashCode() {
25.472 + int result = choiceLimits.length;
25.473 + if (choiceFormats.length > 0) {
25.474 + // enough for reasonable distribution
25.475 + result ^= choiceFormats[choiceFormats.length-1].hashCode();
25.476 + }
25.477 + return result;
25.478 + }
25.479 +
25.480 + /**
25.481 + * Equality comparision between two
25.482 + */
25.483 + public boolean equals(Object obj) {
25.484 + if (obj == null) return false;
25.485 + if (this == obj) // quick check
25.486 + return true;
25.487 + if (getClass() != obj.getClass())
25.488 + return false;
25.489 + ChoiceFormat other = (ChoiceFormat) obj;
25.490 + return (Arrays.equals(choiceLimits, other.choiceLimits)
25.491 + && Arrays.equals(choiceFormats, other.choiceFormats));
25.492 + }
25.493 +
25.494 + /**
25.495 + * After reading an object from the input stream, do a simple verification
25.496 + * to maintain class invariants.
25.497 + * @throws InvalidObjectException if the objects read from the stream is invalid.
25.498 + */
25.499 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
25.500 + in.defaultReadObject();
25.501 + if (choiceLimits.length != choiceFormats.length) {
25.502 + throw new InvalidObjectException(
25.503 + "limits and format arrays of different length.");
25.504 + }
25.505 + }
25.506 +
25.507 + // ===============privates===========================
25.508 +
25.509 + /**
25.510 + * A list of lower bounds for the choices. The formatter will return
25.511 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
25.512 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
25.513 + * @serial
25.514 + */
25.515 + private double[] choiceLimits;
25.516 +
25.517 + /**
25.518 + * A list of choice strings. The formatter will return
25.519 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
25.520 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
25.521 + * @serial
25.522 + */
25.523 + private String[] choiceFormats;
25.524 +
25.525 + /*
25.526 + static final long SIGN = 0x8000000000000000L;
25.527 + static final long EXPONENT = 0x7FF0000000000000L;
25.528 + static final long SIGNIFICAND = 0x000FFFFFFFFFFFFFL;
25.529 +
25.530 + private static double nextDouble (double d, boolean positive) {
25.531 + if (Double.isNaN(d) || Double.isInfinite(d)) {
25.532 + return d;
25.533 + }
25.534 + long bits = Double.doubleToLongBits(d);
25.535 + long significand = bits & SIGNIFICAND;
25.536 + if (bits < 0) {
25.537 + significand |= (SIGN | EXPONENT);
25.538 + }
25.539 + long exponent = bits & EXPONENT;
25.540 + if (positive) {
25.541 + significand += 1;
25.542 + // FIXME fix overflow & underflow
25.543 + } else {
25.544 + significand -= 1;
25.545 + // FIXME fix overflow & underflow
25.546 + }
25.547 + bits = exponent | (significand & ~EXPONENT);
25.548 + return Double.longBitsToDouble(bits);
25.549 + }
25.550 + */
25.551 +
25.552 + static final long SIGN = 0x8000000000000000L;
25.553 + static final long EXPONENT = 0x7FF0000000000000L;
25.554 + static final long POSITIVEINFINITY = 0x7FF0000000000000L;
25.555 +
25.556 + /**
25.557 + * Finds the least double greater than d (if positive == true),
25.558 + * or the greatest double less than d (if positive == false).
25.559 + * If NaN, returns same value.
25.560 + *
25.561 + * Does not affect floating-point flags,
25.562 + * provided these member functions do not:
25.563 + * Double.longBitsToDouble(long)
25.564 + * Double.doubleToLongBits(double)
25.565 + * Double.isNaN(double)
25.566 + */
25.567 + public static double nextDouble (double d, boolean positive) {
25.568 +
25.569 + /* filter out NaN's */
25.570 + if (Double.isNaN(d)) {
25.571 + return d;
25.572 + }
25.573 +
25.574 + /* zero's are also a special case */
25.575 + if (d == 0.0) {
25.576 + double smallestPositiveDouble = Double.longBitsToDouble(1L);
25.577 + if (positive) {
25.578 + return smallestPositiveDouble;
25.579 + } else {
25.580 + return -smallestPositiveDouble;
25.581 + }
25.582 + }
25.583 +
25.584 + /* if entering here, d is a nonzero value */
25.585 +
25.586 + /* hold all bits in a long for later use */
25.587 + long bits = Double.doubleToLongBits(d);
25.588 +
25.589 + /* strip off the sign bit */
25.590 + long magnitude = bits & ~SIGN;
25.591 +
25.592 + /* if next double away from zero, increase magnitude */
25.593 + if ((bits > 0) == positive) {
25.594 + if (magnitude != POSITIVEINFINITY) {
25.595 + magnitude += 1;
25.596 + }
25.597 + }
25.598 + /* else decrease magnitude */
25.599 + else {
25.600 + magnitude -= 1;
25.601 + }
25.602 +
25.603 + /* restore sign bit and return */
25.604 + long signbit = bits & SIGN;
25.605 + return Double.longBitsToDouble (magnitude | signbit);
25.606 + }
25.607 +
25.608 + private static double[] doubleArraySize(double[] array) {
25.609 + int oldSize = array.length;
25.610 + double[] newArray = new double[oldSize * 2];
25.611 + System.arraycopy(array, 0, newArray, 0, oldSize);
25.612 + return newArray;
25.613 + }
25.614 +
25.615 + private String[] doubleArraySize(String[] array) {
25.616 + int oldSize = array.length;
25.617 + String[] newArray = new String[oldSize * 2];
25.618 + System.arraycopy(array, 0, newArray, 0, oldSize);
25.619 + return newArray;
25.620 + }
25.621 +
25.622 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormat.java Thu Oct 03 15:40:35 2013 +0200
26.3 @@ -0,0 +1,1030 @@
26.4 +/*
26.5 + * Copyright (c) 1996, 2010, 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 +
26.29 +/*
26.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
26.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
26.32 + *
26.33 + * The original version of this source code and documentation is copyrighted
26.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
26.35 + * materials are provided under terms of a License Agreement between Taligent
26.36 + * and Sun. This technology is protected by multiple US and International
26.37 + * patents. This notice and attribution to Taligent may not be removed.
26.38 + * Taligent is a registered trademark of Taligent, Inc.
26.39 + *
26.40 + */
26.41 +
26.42 +package java.text;
26.43 +
26.44 +import java.io.InvalidObjectException;
26.45 +import java.text.spi.DateFormatProvider;
26.46 +import java.util.Calendar;
26.47 +import java.util.Date;
26.48 +import java.util.GregorianCalendar;
26.49 +import java.util.HashMap;
26.50 +import java.util.Locale;
26.51 +import java.util.Map;
26.52 +import java.util.MissingResourceException;
26.53 +import java.util.ResourceBundle;
26.54 +import java.util.TimeZone;
26.55 +import java.util.spi.LocaleServiceProvider;
26.56 +import sun.util.LocaleServiceProviderPool;
26.57 +
26.58 +/**
26.59 + * {@code DateFormat} is an abstract class for date/time formatting subclasses which
26.60 + * formats and parses dates or time in a language-independent manner.
26.61 + * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
26.62 + * formatting (i.e., date -> text), parsing (text -> date), and
26.63 + * normalization. The date is represented as a <code>Date</code> object or
26.64 + * as the milliseconds since January 1, 1970, 00:00:00 GMT.
26.65 + *
26.66 + * <p>{@code DateFormat} provides many class methods for obtaining default date/time
26.67 + * formatters based on the default or a given locale and a number of formatting
26.68 + * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
26.69 + * detail and examples of using these styles are provided in the method
26.70 + * descriptions.
26.71 + *
26.72 + * <p>{@code DateFormat} helps you to format and parse dates for any locale.
26.73 + * Your code can be completely independent of the locale conventions for
26.74 + * months, days of the week, or even the calendar format: lunar vs. solar.
26.75 + *
26.76 + * <p>To format a date for the current Locale, use one of the
26.77 + * static factory methods:
26.78 + * <pre>
26.79 + * myString = DateFormat.getDateInstance().format(myDate);
26.80 + * </pre>
26.81 + * <p>If you are formatting multiple dates, it is
26.82 + * more efficient to get the format and use it multiple times so that
26.83 + * the system doesn't have to fetch the information about the local
26.84 + * language and country conventions multiple times.
26.85 + * <pre>
26.86 + * DateFormat df = DateFormat.getDateInstance();
26.87 + * for (int i = 0; i < myDate.length; ++i) {
26.88 + * output.println(df.format(myDate[i]) + "; ");
26.89 + * }
26.90 + * </pre>
26.91 + * <p>To format a date for a different Locale, specify it in the
26.92 + * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
26.93 + * <pre>
26.94 + * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
26.95 + * </pre>
26.96 + * <p>You can use a DateFormat to parse also.
26.97 + * <pre>
26.98 + * myDate = df.parse(myString);
26.99 + * </pre>
26.100 + * <p>Use {@code getDateInstance} to get the normal date format for that country.
26.101 + * There are other static factory methods available.
26.102 + * Use {@code getTimeInstance} to get the time format for that country.
26.103 + * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
26.104 + * different options to these factory methods to control the length of the
26.105 + * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
26.106 + * on the locale, but generally:
26.107 + * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
26.108 + * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
26.109 + * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
26.110 + * <li>{@link #FULL} is pretty completely specified, such as
26.111 + * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
26.112 + * </ul>
26.113 + *
26.114 + * <p>You can also set the time zone on the format if you wish.
26.115 + * If you want even more control over the format or parsing,
26.116 + * (or want to give your users more control),
26.117 + * you can try casting the {@code DateFormat} you get from the factory methods
26.118 + * to a {@link SimpleDateFormat}. This will work for the majority
26.119 + * of countries; just remember to put it in a {@code try} block in case you
26.120 + * encounter an unusual one.
26.121 + *
26.122 + * <p>You can also use forms of the parse and format methods with
26.123 + * {@link ParsePosition} and {@link FieldPosition} to
26.124 + * allow you to
26.125 + * <ul><li>progressively parse through pieces of a string.
26.126 + * <li>align any particular field, or find out where it is for selection
26.127 + * on the screen.
26.128 + * </ul>
26.129 + *
26.130 + * <h4><a name="synchronization">Synchronization</a></h4>
26.131 + *
26.132 + * <p>
26.133 + * Date formats are not synchronized.
26.134 + * It is recommended to create separate format instances for each thread.
26.135 + * If multiple threads access a format concurrently, it must be synchronized
26.136 + * externally.
26.137 + *
26.138 + * @see Format
26.139 + * @see NumberFormat
26.140 + * @see SimpleDateFormat
26.141 + * @see java.util.Calendar
26.142 + * @see java.util.GregorianCalendar
26.143 + * @see java.util.TimeZone
26.144 + * @author Mark Davis, Chen-Lieh Huang, Alan Liu
26.145 + */
26.146 +public abstract class DateFormat extends Format {
26.147 +
26.148 + /**
26.149 + * The {@link Calendar} instance used for calculating the date-time fields
26.150 + * and the instant of time. This field is used for both formatting and
26.151 + * parsing.
26.152 + *
26.153 + * <p>Subclasses should initialize this field to a {@link Calendar}
26.154 + * appropriate for the {@link Locale} associated with this
26.155 + * <code>DateFormat</code>.
26.156 + * @serial
26.157 + */
26.158 + protected Calendar calendar;
26.159 +
26.160 + /**
26.161 + * The number formatter that <code>DateFormat</code> uses to format numbers
26.162 + * in dates and times. Subclasses should initialize this to a number format
26.163 + * appropriate for the locale associated with this <code>DateFormat</code>.
26.164 + * @serial
26.165 + */
26.166 + protected NumberFormat numberFormat;
26.167 +
26.168 + /**
26.169 + * Useful constant for ERA field alignment.
26.170 + * Used in FieldPosition of date/time formatting.
26.171 + */
26.172 + public final static int ERA_FIELD = 0;
26.173 + /**
26.174 + * Useful constant for YEAR field alignment.
26.175 + * Used in FieldPosition of date/time formatting.
26.176 + */
26.177 + public final static int YEAR_FIELD = 1;
26.178 + /**
26.179 + * Useful constant for MONTH field alignment.
26.180 + * Used in FieldPosition of date/time formatting.
26.181 + */
26.182 + public final static int MONTH_FIELD = 2;
26.183 + /**
26.184 + * Useful constant for DATE field alignment.
26.185 + * Used in FieldPosition of date/time formatting.
26.186 + */
26.187 + public final static int DATE_FIELD = 3;
26.188 + /**
26.189 + * Useful constant for one-based HOUR_OF_DAY field alignment.
26.190 + * Used in FieldPosition of date/time formatting.
26.191 + * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
26.192 + * For example, 23:59 + 01:00 results in 24:59.
26.193 + */
26.194 + public final static int HOUR_OF_DAY1_FIELD = 4;
26.195 + /**
26.196 + * Useful constant for zero-based HOUR_OF_DAY field alignment.
26.197 + * Used in FieldPosition of date/time formatting.
26.198 + * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
26.199 + * For example, 23:59 + 01:00 results in 00:59.
26.200 + */
26.201 + public final static int HOUR_OF_DAY0_FIELD = 5;
26.202 + /**
26.203 + * Useful constant for MINUTE field alignment.
26.204 + * Used in FieldPosition of date/time formatting.
26.205 + */
26.206 + public final static int MINUTE_FIELD = 6;
26.207 + /**
26.208 + * Useful constant for SECOND field alignment.
26.209 + * Used in FieldPosition of date/time formatting.
26.210 + */
26.211 + public final static int SECOND_FIELD = 7;
26.212 + /**
26.213 + * Useful constant for MILLISECOND field alignment.
26.214 + * Used in FieldPosition of date/time formatting.
26.215 + */
26.216 + public final static int MILLISECOND_FIELD = 8;
26.217 + /**
26.218 + * Useful constant for DAY_OF_WEEK field alignment.
26.219 + * Used in FieldPosition of date/time formatting.
26.220 + */
26.221 + public final static int DAY_OF_WEEK_FIELD = 9;
26.222 + /**
26.223 + * Useful constant for DAY_OF_YEAR field alignment.
26.224 + * Used in FieldPosition of date/time formatting.
26.225 + */
26.226 + public final static int DAY_OF_YEAR_FIELD = 10;
26.227 + /**
26.228 + * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
26.229 + * Used in FieldPosition of date/time formatting.
26.230 + */
26.231 + public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
26.232 + /**
26.233 + * Useful constant for WEEK_OF_YEAR field alignment.
26.234 + * Used in FieldPosition of date/time formatting.
26.235 + */
26.236 + public final static int WEEK_OF_YEAR_FIELD = 12;
26.237 + /**
26.238 + * Useful constant for WEEK_OF_MONTH field alignment.
26.239 + * Used in FieldPosition of date/time formatting.
26.240 + */
26.241 + public final static int WEEK_OF_MONTH_FIELD = 13;
26.242 + /**
26.243 + * Useful constant for AM_PM field alignment.
26.244 + * Used in FieldPosition of date/time formatting.
26.245 + */
26.246 + public final static int AM_PM_FIELD = 14;
26.247 + /**
26.248 + * Useful constant for one-based HOUR field alignment.
26.249 + * Used in FieldPosition of date/time formatting.
26.250 + * HOUR1_FIELD is used for the one-based 12-hour clock.
26.251 + * For example, 11:30 PM + 1 hour results in 12:30 AM.
26.252 + */
26.253 + public final static int HOUR1_FIELD = 15;
26.254 + /**
26.255 + * Useful constant for zero-based HOUR field alignment.
26.256 + * Used in FieldPosition of date/time formatting.
26.257 + * HOUR0_FIELD is used for the zero-based 12-hour clock.
26.258 + * For example, 11:30 PM + 1 hour results in 00:30 AM.
26.259 + */
26.260 + public final static int HOUR0_FIELD = 16;
26.261 + /**
26.262 + * Useful constant for TIMEZONE field alignment.
26.263 + * Used in FieldPosition of date/time formatting.
26.264 + */
26.265 + public final static int TIMEZONE_FIELD = 17;
26.266 +
26.267 + // Proclaim serial compatibility with 1.1 FCS
26.268 + private static final long serialVersionUID = 7218322306649953788L;
26.269 +
26.270 + /**
26.271 + * Overrides Format.
26.272 + * Formats a time object into a time string. Examples of time objects
26.273 + * are a time value expressed in milliseconds and a Date object.
26.274 + * @param obj must be a Number or a Date.
26.275 + * @param toAppendTo the string buffer for the returning time string.
26.276 + * @return the string buffer passed in as toAppendTo, with formatted text appended.
26.277 + * @param fieldPosition keeps track of the position of the field
26.278 + * within the returned string.
26.279 + * On input: an alignment field,
26.280 + * if desired. On output: the offsets of the alignment field. For
26.281 + * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
26.282 + * if the given fieldPosition is DateFormat.YEAR_FIELD, the
26.283 + * begin index and end index of fieldPosition will be set to
26.284 + * 0 and 4, respectively.
26.285 + * Notice that if the same time field appears
26.286 + * more than once in a pattern, the fieldPosition will be set for the first
26.287 + * occurrence of that time field. For instance, formatting a Date to
26.288 + * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
26.289 + * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
26.290 + * the begin index and end index of fieldPosition will be set to
26.291 + * 5 and 8, respectively, for the first occurrence of the timezone
26.292 + * pattern character 'z'.
26.293 + * @see java.text.Format
26.294 + */
26.295 + public final StringBuffer format(Object obj, StringBuffer toAppendTo,
26.296 + FieldPosition fieldPosition)
26.297 + {
26.298 + if (obj instanceof Date)
26.299 + return format( (Date)obj, toAppendTo, fieldPosition );
26.300 + else if (obj instanceof Number)
26.301 + return format( new Date(((Number)obj).longValue()),
26.302 + toAppendTo, fieldPosition );
26.303 + else
26.304 + throw new IllegalArgumentException("Cannot format given Object as a Date");
26.305 + }
26.306 +
26.307 + /**
26.308 + * Formats a Date into a date/time string.
26.309 + * @param date a Date to be formatted into a date/time string.
26.310 + * @param toAppendTo the string buffer for the returning date/time string.
26.311 + * @param fieldPosition keeps track of the position of the field
26.312 + * within the returned string.
26.313 + * On input: an alignment field,
26.314 + * if desired. On output: the offsets of the alignment field. For
26.315 + * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
26.316 + * if the given fieldPosition is DateFormat.YEAR_FIELD, the
26.317 + * begin index and end index of fieldPosition will be set to
26.318 + * 0 and 4, respectively.
26.319 + * Notice that if the same time field appears
26.320 + * more than once in a pattern, the fieldPosition will be set for the first
26.321 + * occurrence of that time field. For instance, formatting a Date to
26.322 + * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
26.323 + * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
26.324 + * the begin index and end index of fieldPosition will be set to
26.325 + * 5 and 8, respectively, for the first occurrence of the timezone
26.326 + * pattern character 'z'.
26.327 + * @return the string buffer passed in as toAppendTo, with formatted text appended.
26.328 + */
26.329 + public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
26.330 + FieldPosition fieldPosition);
26.331 +
26.332 + /**
26.333 + * Formats a Date into a date/time string.
26.334 + * @param date the time value to be formatted into a time string.
26.335 + * @return the formatted time string.
26.336 + */
26.337 + public final String format(Date date)
26.338 + {
26.339 + return format(date, new StringBuffer(),
26.340 + DontCareFieldPosition.INSTANCE).toString();
26.341 + }
26.342 +
26.343 + /**
26.344 + * Parses text from the beginning of the given string to produce a date.
26.345 + * The method may not use the entire text of the given string.
26.346 + * <p>
26.347 + * See the {@link #parse(String, ParsePosition)} method for more information
26.348 + * on date parsing.
26.349 + *
26.350 + * @param source A <code>String</code> whose beginning should be parsed.
26.351 + * @return A <code>Date</code> parsed from the string.
26.352 + * @exception ParseException if the beginning of the specified string
26.353 + * cannot be parsed.
26.354 + */
26.355 + public Date parse(String source) throws ParseException
26.356 + {
26.357 + ParsePosition pos = new ParsePosition(0);
26.358 + Date result = parse(source, pos);
26.359 + if (pos.index == 0)
26.360 + throw new ParseException("Unparseable date: \"" + source + "\"" ,
26.361 + pos.errorIndex);
26.362 + return result;
26.363 + }
26.364 +
26.365 + /**
26.366 + * Parse a date/time string according to the given parse position. For
26.367 + * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
26.368 + * that is equivalent to {@code Date(837039900000L)}.
26.369 + *
26.370 + * <p> By default, parsing is lenient: If the input is not in the form used
26.371 + * by this object's format method but can still be parsed as a date, then
26.372 + * the parse succeeds. Clients may insist on strict adherence to the
26.373 + * format by calling {@link #setLenient(boolean) setLenient(false)}.
26.374 + *
26.375 + * <p>This parsing operation uses the {@link #calendar} to produce
26.376 + * a {@code Date}. As a result, the {@code calendar}'s date-time
26.377 + * fields and the {@code TimeZone} value may have been
26.378 + * overwritten, depending on subclass implementations. Any {@code
26.379 + * TimeZone} value that has previously been set by a call to
26.380 + * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
26.381 + * to be restored for further operations.
26.382 + *
26.383 + * @param source The date/time string to be parsed
26.384 + *
26.385 + * @param pos On input, the position at which to start parsing; on
26.386 + * output, the position at which parsing terminated, or the
26.387 + * start position if the parse failed.
26.388 + *
26.389 + * @return A {@code Date}, or {@code null} if the input could not be parsed
26.390 + */
26.391 + public abstract Date parse(String source, ParsePosition pos);
26.392 +
26.393 + /**
26.394 + * Parses text from a string to produce a <code>Date</code>.
26.395 + * <p>
26.396 + * The method attempts to parse text starting at the index given by
26.397 + * <code>pos</code>.
26.398 + * If parsing succeeds, then the index of <code>pos</code> is updated
26.399 + * to the index after the last character used (parsing does not necessarily
26.400 + * use all characters up to the end of the string), and the parsed
26.401 + * date is returned. The updated <code>pos</code> can be used to
26.402 + * indicate the starting point for the next call to this method.
26.403 + * If an error occurs, then the index of <code>pos</code> is not
26.404 + * changed, the error index of <code>pos</code> is set to the index of
26.405 + * the character where the error occurred, and null is returned.
26.406 + * <p>
26.407 + * See the {@link #parse(String, ParsePosition)} method for more information
26.408 + * on date parsing.
26.409 + *
26.410 + * @param source A <code>String</code>, part of which should be parsed.
26.411 + * @param pos A <code>ParsePosition</code> object with index and error
26.412 + * index information as described above.
26.413 + * @return A <code>Date</code> parsed from the string. In case of
26.414 + * error, returns null.
26.415 + * @exception NullPointerException if <code>pos</code> is null.
26.416 + */
26.417 + public Object parseObject(String source, ParsePosition pos) {
26.418 + return parse(source, pos);
26.419 + }
26.420 +
26.421 + /**
26.422 + * Constant for full style pattern.
26.423 + */
26.424 + public static final int FULL = 0;
26.425 + /**
26.426 + * Constant for long style pattern.
26.427 + */
26.428 + public static final int LONG = 1;
26.429 + /**
26.430 + * Constant for medium style pattern.
26.431 + */
26.432 + public static final int MEDIUM = 2;
26.433 + /**
26.434 + * Constant for short style pattern.
26.435 + */
26.436 + public static final int SHORT = 3;
26.437 + /**
26.438 + * Constant for default style pattern. Its value is MEDIUM.
26.439 + */
26.440 + public static final int DEFAULT = MEDIUM;
26.441 +
26.442 + /**
26.443 + * Gets the time formatter with the default formatting style
26.444 + * for the default locale.
26.445 + * @return a time formatter.
26.446 + */
26.447 + public final static DateFormat getTimeInstance()
26.448 + {
26.449 + return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
26.450 + }
26.451 +
26.452 + /**
26.453 + * Gets the time formatter with the given formatting style
26.454 + * for the default locale.
26.455 + * @param style the given formatting style. For example,
26.456 + * SHORT for "h:mm a" in the US locale.
26.457 + * @return a time formatter.
26.458 + */
26.459 + public final static DateFormat getTimeInstance(int style)
26.460 + {
26.461 + return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
26.462 + }
26.463 +
26.464 + /**
26.465 + * Gets the time formatter with the given formatting style
26.466 + * for the given locale.
26.467 + * @param style the given formatting style. For example,
26.468 + * SHORT for "h:mm a" in the US locale.
26.469 + * @param aLocale the given locale.
26.470 + * @return a time formatter.
26.471 + */
26.472 + public final static DateFormat getTimeInstance(int style,
26.473 + Locale aLocale)
26.474 + {
26.475 + return get(style, 0, 1, aLocale);
26.476 + }
26.477 +
26.478 + /**
26.479 + * Gets the date formatter with the default formatting style
26.480 + * for the default locale.
26.481 + * @return a date formatter.
26.482 + */
26.483 + public final static DateFormat getDateInstance()
26.484 + {
26.485 + return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
26.486 + }
26.487 +
26.488 + /**
26.489 + * Gets the date formatter with the given formatting style
26.490 + * for the default locale.
26.491 + * @param style the given formatting style. For example,
26.492 + * SHORT for "M/d/yy" in the US locale.
26.493 + * @return a date formatter.
26.494 + */
26.495 + public final static DateFormat getDateInstance(int style)
26.496 + {
26.497 + return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
26.498 + }
26.499 +
26.500 + /**
26.501 + * Gets the date formatter with the given formatting style
26.502 + * for the given locale.
26.503 + * @param style the given formatting style. For example,
26.504 + * SHORT for "M/d/yy" in the US locale.
26.505 + * @param aLocale the given locale.
26.506 + * @return a date formatter.
26.507 + */
26.508 + public final static DateFormat getDateInstance(int style,
26.509 + Locale aLocale)
26.510 + {
26.511 + return get(0, style, 2, aLocale);
26.512 + }
26.513 +
26.514 + /**
26.515 + * Gets the date/time formatter with the default formatting style
26.516 + * for the default locale.
26.517 + * @return a date/time formatter.
26.518 + */
26.519 + public final static DateFormat getDateTimeInstance()
26.520 + {
26.521 + return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
26.522 + }
26.523 +
26.524 + /**
26.525 + * Gets the date/time formatter with the given date and time
26.526 + * formatting styles for the default locale.
26.527 + * @param dateStyle the given date formatting style. For example,
26.528 + * SHORT for "M/d/yy" in the US locale.
26.529 + * @param timeStyle the given time formatting style. For example,
26.530 + * SHORT for "h:mm a" in the US locale.
26.531 + * @return a date/time formatter.
26.532 + */
26.533 + public final static DateFormat getDateTimeInstance(int dateStyle,
26.534 + int timeStyle)
26.535 + {
26.536 + return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
26.537 + }
26.538 +
26.539 + /**
26.540 + * Gets the date/time formatter with the given formatting styles
26.541 + * for the given locale.
26.542 + * @param dateStyle the given date formatting style.
26.543 + * @param timeStyle the given time formatting style.
26.544 + * @param aLocale the given locale.
26.545 + * @return a date/time formatter.
26.546 + */
26.547 + public final static DateFormat
26.548 + getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
26.549 + {
26.550 + return get(timeStyle, dateStyle, 3, aLocale);
26.551 + }
26.552 +
26.553 + /**
26.554 + * Get a default date/time formatter that uses the SHORT style for both the
26.555 + * date and the time.
26.556 + */
26.557 + public final static DateFormat getInstance() {
26.558 + return getDateTimeInstance(SHORT, SHORT);
26.559 + }
26.560 +
26.561 + /**
26.562 + * Returns an array of all locales for which the
26.563 + * <code>get*Instance</code> methods of this class can return
26.564 + * localized instances.
26.565 + * The returned array represents the union of locales supported by the Java
26.566 + * runtime and by installed
26.567 + * {@link java.text.spi.DateFormatProvider DateFormatProvider} implementations.
26.568 + * It must contain at least a <code>Locale</code> instance equal to
26.569 + * {@link java.util.Locale#US Locale.US}.
26.570 + *
26.571 + * @return An array of locales for which localized
26.572 + * <code>DateFormat</code> instances are available.
26.573 + */
26.574 + public static Locale[] getAvailableLocales()
26.575 + {
26.576 + LocaleServiceProviderPool pool =
26.577 + LocaleServiceProviderPool.getPool(DateFormatProvider.class);
26.578 + return pool.getAvailableLocales();
26.579 + }
26.580 +
26.581 + /**
26.582 + * Set the calendar to be used by this date format. Initially, the default
26.583 + * calendar for the specified or default locale is used.
26.584 + *
26.585 + * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
26.586 + * #isLenient() leniency} values that have previously been set are
26.587 + * overwritten by {@code newCalendar}'s values.
26.588 + *
26.589 + * @param newCalendar the new {@code Calendar} to be used by the date format
26.590 + */
26.591 + public void setCalendar(Calendar newCalendar)
26.592 + {
26.593 + this.calendar = newCalendar;
26.594 + }
26.595 +
26.596 + /**
26.597 + * Gets the calendar associated with this date/time formatter.
26.598 + *
26.599 + * @return the calendar associated with this date/time formatter.
26.600 + */
26.601 + public Calendar getCalendar()
26.602 + {
26.603 + return calendar;
26.604 + }
26.605 +
26.606 + /**
26.607 + * Allows you to set the number formatter.
26.608 + * @param newNumberFormat the given new NumberFormat.
26.609 + */
26.610 + public void setNumberFormat(NumberFormat newNumberFormat)
26.611 + {
26.612 + this.numberFormat = newNumberFormat;
26.613 + }
26.614 +
26.615 + /**
26.616 + * Gets the number formatter which this date/time formatter uses to
26.617 + * format and parse a time.
26.618 + * @return the number formatter which this date/time formatter uses.
26.619 + */
26.620 + public NumberFormat getNumberFormat()
26.621 + {
26.622 + return numberFormat;
26.623 + }
26.624 +
26.625 + /**
26.626 + * Sets the time zone for the calendar of this {@code DateFormat} object.
26.627 + * This method is equivalent to the following call.
26.628 + * <blockquote><pre>
26.629 + * getCalendar().setTimeZone(zone)
26.630 + * </pre></blockquote>
26.631 + *
26.632 + * <p>The {@code TimeZone} set by this method is overwritten by a
26.633 + * {@link #setCalendar(java.util.Calendar) setCalendar} call.
26.634 + *
26.635 + * <p>The {@code TimeZone} set by this method may be overwritten as
26.636 + * a result of a call to the parse method.
26.637 + *
26.638 + * @param zone the given new time zone.
26.639 + */
26.640 + public void setTimeZone(TimeZone zone)
26.641 + {
26.642 + calendar.setTimeZone(zone);
26.643 + }
26.644 +
26.645 + /**
26.646 + * Gets the time zone.
26.647 + * This method is equivalent to the following call.
26.648 + * <blockquote><pre>
26.649 + * getCalendar().getTimeZone()
26.650 + * </pre></blockquote>
26.651 + *
26.652 + * @return the time zone associated with the calendar of DateFormat.
26.653 + */
26.654 + public TimeZone getTimeZone()
26.655 + {
26.656 + return calendar.getTimeZone();
26.657 + }
26.658 +
26.659 + /**
26.660 + * Specify whether or not date/time parsing is to be lenient. With
26.661 + * lenient parsing, the parser may use heuristics to interpret inputs that
26.662 + * do not precisely match this object's format. With strict parsing,
26.663 + * inputs must match this object's format.
26.664 + *
26.665 + * <p>This method is equivalent to the following call.
26.666 + * <blockquote><pre>
26.667 + * getCalendar().setLenient(lenient)
26.668 + * </pre></blockquote>
26.669 + *
26.670 + * <p>This leniency value is overwritten by a call to {@link
26.671 + * #setCalendar(java.util.Calendar) setCalendar()}.
26.672 + *
26.673 + * @param lenient when {@code true}, parsing is lenient
26.674 + * @see java.util.Calendar#setLenient(boolean)
26.675 + */
26.676 + public void setLenient(boolean lenient)
26.677 + {
26.678 + calendar.setLenient(lenient);
26.679 + }
26.680 +
26.681 + /**
26.682 + * Tell whether date/time parsing is to be lenient.
26.683 + * This method is equivalent to the following call.
26.684 + * <blockquote><pre>
26.685 + * getCalendar().isLenient()
26.686 + * </pre></blockquote>
26.687 + *
26.688 + * @return {@code true} if the {@link #calendar} is lenient;
26.689 + * {@code false} otherwise.
26.690 + * @see java.util.Calendar#isLenient()
26.691 + */
26.692 + public boolean isLenient()
26.693 + {
26.694 + return calendar.isLenient();
26.695 + }
26.696 +
26.697 + /**
26.698 + * Overrides hashCode
26.699 + */
26.700 + public int hashCode() {
26.701 + return numberFormat.hashCode();
26.702 + // just enough fields for a reasonable distribution
26.703 + }
26.704 +
26.705 + /**
26.706 + * Overrides equals
26.707 + */
26.708 + public boolean equals(Object obj) {
26.709 + if (this == obj) return true;
26.710 + if (obj == null || getClass() != obj.getClass()) return false;
26.711 + DateFormat other = (DateFormat) obj;
26.712 + return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
26.713 + calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
26.714 + calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
26.715 + calendar.isLenient() == other.calendar.isLenient() &&
26.716 + calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
26.717 + numberFormat.equals(other.numberFormat));
26.718 + }
26.719 +
26.720 + /**
26.721 + * Overrides Cloneable
26.722 + */
26.723 + public Object clone()
26.724 + {
26.725 + DateFormat other = (DateFormat) super.clone();
26.726 + other.calendar = (Calendar) calendar.clone();
26.727 + other.numberFormat = (NumberFormat) numberFormat.clone();
26.728 + return other;
26.729 + }
26.730 +
26.731 + /**
26.732 + * Creates a DateFormat with the given time and/or date style in the given
26.733 + * locale.
26.734 + * @param timeStyle a value from 0 to 3 indicating the time format,
26.735 + * ignored if flags is 2
26.736 + * @param dateStyle a value from 0 to 3 indicating the time format,
26.737 + * ignored if flags is 1
26.738 + * @param flags either 1 for a time format, 2 for a date format,
26.739 + * or 3 for a date/time format
26.740 + * @param loc the locale for the format
26.741 + */
26.742 + private static DateFormat get(int timeStyle, int dateStyle,
26.743 + int flags, Locale loc) {
26.744 + if ((flags & 1) != 0) {
26.745 + if (timeStyle < 0 || timeStyle > 3) {
26.746 + throw new IllegalArgumentException("Illegal time style " + timeStyle);
26.747 + }
26.748 + } else {
26.749 + timeStyle = -1;
26.750 + }
26.751 + if ((flags & 2) != 0) {
26.752 + if (dateStyle < 0 || dateStyle > 3) {
26.753 + throw new IllegalArgumentException("Illegal date style " + dateStyle);
26.754 + }
26.755 + } else {
26.756 + dateStyle = -1;
26.757 + }
26.758 + try {
26.759 + // Check whether a provider can provide an implementation that's closer
26.760 + // to the requested locale than what the Java runtime itself can provide.
26.761 + LocaleServiceProviderPool pool =
26.762 + LocaleServiceProviderPool.getPool(DateFormatProvider.class);
26.763 + if (pool.hasProviders()) {
26.764 + DateFormat providersInstance = pool.getLocalizedObject(
26.765 + DateFormatGetter.INSTANCE,
26.766 + loc,
26.767 + timeStyle,
26.768 + dateStyle,
26.769 + flags);
26.770 + if (providersInstance != null) {
26.771 + return providersInstance;
26.772 + }
26.773 + }
26.774 +
26.775 + return new SimpleDateFormat(timeStyle, dateStyle, loc);
26.776 + } catch (MissingResourceException e) {
26.777 + return new SimpleDateFormat("M/d/yy h:mm a");
26.778 + }
26.779 + }
26.780 +
26.781 + /**
26.782 + * Create a new date format.
26.783 + */
26.784 + protected DateFormat() {}
26.785 +
26.786 + /**
26.787 + * Defines constants that are used as attribute keys in the
26.788 + * <code>AttributedCharacterIterator</code> returned
26.789 + * from <code>DateFormat.formatToCharacterIterator</code> and as
26.790 + * field identifiers in <code>FieldPosition</code>.
26.791 + * <p>
26.792 + * The class also provides two methods to map
26.793 + * between its constants and the corresponding Calendar constants.
26.794 + *
26.795 + * @since 1.4
26.796 + * @see java.util.Calendar
26.797 + */
26.798 + public static class Field extends Format.Field {
26.799 +
26.800 + // Proclaim serial compatibility with 1.4 FCS
26.801 + private static final long serialVersionUID = 7441350119349544720L;
26.802 +
26.803 + // table of all instances in this class, used by readResolve
26.804 + private static final Map instanceMap = new HashMap(18);
26.805 + // Maps from Calendar constant (such as Calendar.ERA) to Field
26.806 + // constant (such as Field.ERA).
26.807 + private static final Field[] calendarToFieldMapping =
26.808 + new Field[Calendar.FIELD_COUNT];
26.809 +
26.810 + /** Calendar field. */
26.811 + private int calendarField;
26.812 +
26.813 + /**
26.814 + * Returns the <code>Field</code> constant that corresponds to
26.815 + * the <code>Calendar</code> constant <code>calendarField</code>.
26.816 + * If there is no direct mapping between the <code>Calendar</code>
26.817 + * constant and a <code>Field</code>, null is returned.
26.818 + *
26.819 + * @throws IllegalArgumentException if <code>calendarField</code> is
26.820 + * not the value of a <code>Calendar</code> field constant.
26.821 + * @param calendarField Calendar field constant
26.822 + * @return Field instance representing calendarField.
26.823 + * @see java.util.Calendar
26.824 + */
26.825 + public static Field ofCalendarField(int calendarField) {
26.826 + if (calendarField < 0 || calendarField >=
26.827 + calendarToFieldMapping.length) {
26.828 + throw new IllegalArgumentException("Unknown Calendar constant "
26.829 + + calendarField);
26.830 + }
26.831 + return calendarToFieldMapping[calendarField];
26.832 + }
26.833 +
26.834 + /**
26.835 + * Creates a <code>Field</code>.
26.836 + *
26.837 + * @param name the name of the <code>Field</code>
26.838 + * @param calendarField the <code>Calendar</code> constant this
26.839 + * <code>Field</code> corresponds to; any value, even one
26.840 + * outside the range of legal <code>Calendar</code> values may
26.841 + * be used, but <code>-1</code> should be used for values
26.842 + * that don't correspond to legal <code>Calendar</code> values
26.843 + */
26.844 + protected Field(String name, int calendarField) {
26.845 + super(name);
26.846 + this.calendarField = calendarField;
26.847 + if (this.getClass() == DateFormat.Field.class) {
26.848 + instanceMap.put(name, this);
26.849 + if (calendarField >= 0) {
26.850 + // assert(calendarField < Calendar.FIELD_COUNT);
26.851 + calendarToFieldMapping[calendarField] = this;
26.852 + }
26.853 + }
26.854 + }
26.855 +
26.856 + /**
26.857 + * Returns the <code>Calendar</code> field associated with this
26.858 + * attribute. For example, if this represents the hours field of
26.859 + * a <code>Calendar</code>, this would return
26.860 + * <code>Calendar.HOUR</code>. If there is no corresponding
26.861 + * <code>Calendar</code> constant, this will return -1.
26.862 + *
26.863 + * @return Calendar constant for this field
26.864 + * @see java.util.Calendar
26.865 + */
26.866 + public int getCalendarField() {
26.867 + return calendarField;
26.868 + }
26.869 +
26.870 + /**
26.871 + * Resolves instances being deserialized to the predefined constants.
26.872 + *
26.873 + * @throws InvalidObjectException if the constant could not be
26.874 + * resolved.
26.875 + * @return resolved DateFormat.Field constant
26.876 + */
26.877 + protected Object readResolve() throws InvalidObjectException {
26.878 + if (this.getClass() != DateFormat.Field.class) {
26.879 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
26.880 + }
26.881 +
26.882 + Object instance = instanceMap.get(getName());
26.883 + if (instance != null) {
26.884 + return instance;
26.885 + } else {
26.886 + throw new InvalidObjectException("unknown attribute name");
26.887 + }
26.888 + }
26.889 +
26.890 + //
26.891 + // The constants
26.892 + //
26.893 +
26.894 + /**
26.895 + * Constant identifying the era field.
26.896 + */
26.897 + public final static Field ERA = new Field("era", Calendar.ERA);
26.898 +
26.899 + /**
26.900 + * Constant identifying the year field.
26.901 + */
26.902 + public final static Field YEAR = new Field("year", Calendar.YEAR);
26.903 +
26.904 + /**
26.905 + * Constant identifying the month field.
26.906 + */
26.907 + public final static Field MONTH = new Field("month", Calendar.MONTH);
26.908 +
26.909 + /**
26.910 + * Constant identifying the day of month field.
26.911 + */
26.912 + public final static Field DAY_OF_MONTH = new
26.913 + Field("day of month", Calendar.DAY_OF_MONTH);
26.914 +
26.915 + /**
26.916 + * Constant identifying the hour of day field, where the legal values
26.917 + * are 1 to 24.
26.918 + */
26.919 + public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
26.920 +
26.921 + /**
26.922 + * Constant identifying the hour of day field, where the legal values
26.923 + * are 0 to 23.
26.924 + */
26.925 + public final static Field HOUR_OF_DAY0 = new
26.926 + Field("hour of day", Calendar.HOUR_OF_DAY);
26.927 +
26.928 + /**
26.929 + * Constant identifying the minute field.
26.930 + */
26.931 + public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
26.932 +
26.933 + /**
26.934 + * Constant identifying the second field.
26.935 + */
26.936 + public final static Field SECOND =new Field("second", Calendar.SECOND);
26.937 +
26.938 + /**
26.939 + * Constant identifying the millisecond field.
26.940 + */
26.941 + public final static Field MILLISECOND = new
26.942 + Field("millisecond", Calendar.MILLISECOND);
26.943 +
26.944 + /**
26.945 + * Constant identifying the day of week field.
26.946 + */
26.947 + public final static Field DAY_OF_WEEK = new
26.948 + Field("day of week", Calendar.DAY_OF_WEEK);
26.949 +
26.950 + /**
26.951 + * Constant identifying the day of year field.
26.952 + */
26.953 + public final static Field DAY_OF_YEAR = new
26.954 + Field("day of year", Calendar.DAY_OF_YEAR);
26.955 +
26.956 + /**
26.957 + * Constant identifying the day of week field.
26.958 + */
26.959 + public final static Field DAY_OF_WEEK_IN_MONTH =
26.960 + new Field("day of week in month",
26.961 + Calendar.DAY_OF_WEEK_IN_MONTH);
26.962 +
26.963 + /**
26.964 + * Constant identifying the week of year field.
26.965 + */
26.966 + public final static Field WEEK_OF_YEAR = new
26.967 + Field("week of year", Calendar.WEEK_OF_YEAR);
26.968 +
26.969 + /**
26.970 + * Constant identifying the week of month field.
26.971 + */
26.972 + public final static Field WEEK_OF_MONTH = new
26.973 + Field("week of month", Calendar.WEEK_OF_MONTH);
26.974 +
26.975 + /**
26.976 + * Constant identifying the time of day indicator
26.977 + * (e.g. "a.m." or "p.m.") field.
26.978 + */
26.979 + public final static Field AM_PM = new
26.980 + Field("am pm", Calendar.AM_PM);
26.981 +
26.982 + /**
26.983 + * Constant identifying the hour field, where the legal values are
26.984 + * 1 to 12.
26.985 + */
26.986 + public final static Field HOUR1 = new Field("hour 1", -1);
26.987 +
26.988 + /**
26.989 + * Constant identifying the hour field, where the legal values are
26.990 + * 0 to 11.
26.991 + */
26.992 + public final static Field HOUR0 = new
26.993 + Field("hour", Calendar.HOUR);
26.994 +
26.995 + /**
26.996 + * Constant identifying the time zone field.
26.997 + */
26.998 + public final static Field TIME_ZONE = new Field("time zone", -1);
26.999 + }
26.1000 +
26.1001 + /**
26.1002 + * Obtains a DateFormat instance from a DateFormatProvider
26.1003 + * implementation.
26.1004 + */
26.1005 + private static class DateFormatGetter
26.1006 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatProvider, DateFormat> {
26.1007 + private static final DateFormatGetter INSTANCE = new DateFormatGetter();
26.1008 +
26.1009 + public DateFormat getObject(DateFormatProvider dateFormatProvider,
26.1010 + Locale locale,
26.1011 + String key,
26.1012 + Object... params) {
26.1013 + assert params.length == 3;
26.1014 +
26.1015 + int timeStyle = (Integer)params[0];
26.1016 + int dateStyle = (Integer)params[1];
26.1017 + int flags = (Integer)params[2];
26.1018 +
26.1019 + switch (flags) {
26.1020 + case 1:
26.1021 + return dateFormatProvider.getTimeInstance(timeStyle, locale);
26.1022 + case 2:
26.1023 + return dateFormatProvider.getDateInstance(dateStyle, locale);
26.1024 + case 3:
26.1025 + return dateFormatProvider.getDateTimeInstance(dateStyle, timeStyle, locale);
26.1026 + default:
26.1027 + assert false : "should not happen";
26.1028 + }
26.1029 +
26.1030 + return null;
26.1031 + }
26.1032 + }
26.1033 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormatSymbols.java Thu Oct 03 15:40:35 2013 +0200
27.3 @@ -0,0 +1,794 @@
27.4 +/*
27.5 + * Copyright (c) 1996, 2010, 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 - All Rights Reserved
27.31 + * (C) Copyright IBM Corp. 1996 - 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.IOException;
27.45 +import java.io.ObjectOutputStream;
27.46 +import java.io.Serializable;
27.47 +import java.lang.ref.SoftReference;
27.48 +import java.text.spi.DateFormatSymbolsProvider;
27.49 +import java.util.Arrays;
27.50 +import java.util.List;
27.51 +import java.util.Locale;
27.52 +import java.util.ResourceBundle;
27.53 +import java.util.TimeZone;
27.54 +import java.util.concurrent.ConcurrentHashMap;
27.55 +import java.util.concurrent.ConcurrentMap;
27.56 +import java.util.spi.LocaleServiceProvider;
27.57 +import sun.util.LocaleServiceProviderPool;
27.58 +import sun.util.TimeZoneNameUtility;
27.59 +import sun.util.calendar.ZoneInfo;
27.60 +import sun.util.resources.LocaleData;
27.61 +
27.62 +/**
27.63 + * <code>DateFormatSymbols</code> is a public class for encapsulating
27.64 + * localizable date-time formatting data, such as the names of the
27.65 + * months, the names of the days of the week, and the time zone data.
27.66 + * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
27.67 + * <code>DateFormatSymbols</code> to encapsulate this information.
27.68 + *
27.69 + * <p>
27.70 + * Typically you shouldn't use <code>DateFormatSymbols</code> directly.
27.71 + * Rather, you are encouraged to create a date-time formatter with the
27.72 + * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
27.73 + * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
27.74 + * These methods automatically create a <code>DateFormatSymbols</code> for
27.75 + * the formatter so that you don't have to. After the
27.76 + * formatter is created, you may modify its format pattern using the
27.77 + * <code>setPattern</code> method. For more information about
27.78 + * creating formatters using <code>DateFormat</code>'s factory methods,
27.79 + * see {@link DateFormat}.
27.80 + *
27.81 + * <p>
27.82 + * If you decide to create a date-time formatter with a specific
27.83 + * format pattern for a specific locale, you can do so with:
27.84 + * <blockquote>
27.85 + * <pre>
27.86 + * new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
27.87 + * </pre>
27.88 + * </blockquote>
27.89 + *
27.90 + * <p>
27.91 + * <code>DateFormatSymbols</code> objects are cloneable. When you obtain
27.92 + * a <code>DateFormatSymbols</code> object, feel free to modify the
27.93 + * date-time formatting data. For instance, you can replace the localized
27.94 + * date-time format pattern characters with the ones that you feel easy
27.95 + * to remember. Or you can change the representative cities
27.96 + * to your favorite ones.
27.97 + *
27.98 + * <p>
27.99 + * New <code>DateFormatSymbols</code> subclasses may be added to support
27.100 + * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
27.101 +
27.102 + * @see DateFormat
27.103 + * @see SimpleDateFormat
27.104 + * @see java.util.SimpleTimeZone
27.105 + * @author Chen-Lieh Huang
27.106 + */
27.107 +public class DateFormatSymbols implements Serializable, Cloneable {
27.108 +
27.109 + /**
27.110 + * Construct a DateFormatSymbols object by loading format data from
27.111 + * resources for the default locale. This constructor can only
27.112 + * construct instances for the locales supported by the Java
27.113 + * runtime environment, not for those supported by installed
27.114 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
27.115 + * implementations. For full locale coverage, use the
27.116 + * {@link #getInstance(Locale) getInstance} method.
27.117 + *
27.118 + * @see #getInstance()
27.119 + * @exception java.util.MissingResourceException
27.120 + * if the resources for the default locale cannot be
27.121 + * found or cannot be loaded.
27.122 + */
27.123 + public DateFormatSymbols()
27.124 + {
27.125 + initializeData(Locale.getDefault(Locale.Category.FORMAT));
27.126 + }
27.127 +
27.128 + /**
27.129 + * Construct a DateFormatSymbols object by loading format data from
27.130 + * resources for the given locale. This constructor can only
27.131 + * construct instances for the locales supported by the Java
27.132 + * runtime environment, not for those supported by installed
27.133 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
27.134 + * implementations. For full locale coverage, use the
27.135 + * {@link #getInstance(Locale) getInstance} method.
27.136 + *
27.137 + * @see #getInstance(Locale)
27.138 + * @exception java.util.MissingResourceException
27.139 + * if the resources for the specified locale cannot be
27.140 + * found or cannot be loaded.
27.141 + */
27.142 + public DateFormatSymbols(Locale locale)
27.143 + {
27.144 + initializeData(locale);
27.145 + }
27.146 +
27.147 + /**
27.148 + * Era strings. For example: "AD" and "BC". An array of 2 strings,
27.149 + * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
27.150 + * @serial
27.151 + */
27.152 + String eras[] = null;
27.153 +
27.154 + /**
27.155 + * Month strings. For example: "January", "February", etc. An array
27.156 + * of 13 strings (some calendars have 13 months), indexed by
27.157 + * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
27.158 + * @serial
27.159 + */
27.160 + String months[] = null;
27.161 +
27.162 + /**
27.163 + * Short month strings. For example: "Jan", "Feb", etc. An array of
27.164 + * 13 strings (some calendars have 13 months), indexed by
27.165 + * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
27.166 +
27.167 + * @serial
27.168 + */
27.169 + String shortMonths[] = null;
27.170 +
27.171 + /**
27.172 + * Weekday strings. For example: "Sunday", "Monday", etc. An array
27.173 + * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
27.174 + * <code>Calendar.MONDAY</code>, etc.
27.175 + * The element <code>weekdays[0]</code> is ignored.
27.176 + * @serial
27.177 + */
27.178 + String weekdays[] = null;
27.179 +
27.180 + /**
27.181 + * Short weekday strings. For example: "Sun", "Mon", etc. An array
27.182 + * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
27.183 + * <code>Calendar.MONDAY</code>, etc.
27.184 + * The element <code>shortWeekdays[0]</code> is ignored.
27.185 + * @serial
27.186 + */
27.187 + String shortWeekdays[] = null;
27.188 +
27.189 + /**
27.190 + * AM and PM strings. For example: "AM" and "PM". An array of
27.191 + * 2 strings, indexed by <code>Calendar.AM</code> and
27.192 + * <code>Calendar.PM</code>.
27.193 + * @serial
27.194 + */
27.195 + String ampms[] = null;
27.196 +
27.197 + /**
27.198 + * Localized names of time zones in this locale. This is a
27.199 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
27.200 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
27.201 + * entry containing the localized names for a single <code>TimeZone</code>.
27.202 + * Each such row contains (with <code>i</code> ranging from
27.203 + * 0..<em>n</em>-1):
27.204 + * <ul>
27.205 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
27.206 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
27.207 + * time</li>
27.208 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
27.209 + * standard time</li>
27.210 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
27.211 + * saving time</li>
27.212 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
27.213 + * saving time</li>
27.214 + * </ul>
27.215 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
27.216 + * the {@link java.util.TimeZone TimeZone} class that are not
27.217 + * <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
27.218 + * All other entries are localized names.
27.219 + * @see java.util.TimeZone
27.220 + * @serial
27.221 + */
27.222 + String zoneStrings[][] = null;
27.223 +
27.224 + /**
27.225 + * Indicates that zoneStrings is set externally with setZoneStrings() method.
27.226 + */
27.227 + transient boolean isZoneStringsSet = false;
27.228 +
27.229 + /**
27.230 + * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
27.231 + * All locales use the same these unlocalized pattern characters.
27.232 + */
27.233 + static final String patternChars = "GyMdkHmsSEDFwWahKzZYuX";
27.234 +
27.235 + static final int PATTERN_ERA = 0; // G
27.236 + static final int PATTERN_YEAR = 1; // y
27.237 + static final int PATTERN_MONTH = 2; // M
27.238 + static final int PATTERN_DAY_OF_MONTH = 3; // d
27.239 + static final int PATTERN_HOUR_OF_DAY1 = 4; // k
27.240 + static final int PATTERN_HOUR_OF_DAY0 = 5; // H
27.241 + static final int PATTERN_MINUTE = 6; // m
27.242 + static final int PATTERN_SECOND = 7; // s
27.243 + static final int PATTERN_MILLISECOND = 8; // S
27.244 + static final int PATTERN_DAY_OF_WEEK = 9; // E
27.245 + static final int PATTERN_DAY_OF_YEAR = 10; // D
27.246 + static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
27.247 + static final int PATTERN_WEEK_OF_YEAR = 12; // w
27.248 + static final int PATTERN_WEEK_OF_MONTH = 13; // W
27.249 + static final int PATTERN_AM_PM = 14; // a
27.250 + static final int PATTERN_HOUR1 = 15; // h
27.251 + static final int PATTERN_HOUR0 = 16; // K
27.252 + static final int PATTERN_ZONE_NAME = 17; // z
27.253 + static final int PATTERN_ZONE_VALUE = 18; // Z
27.254 + static final int PATTERN_WEEK_YEAR = 19; // Y
27.255 + static final int PATTERN_ISO_DAY_OF_WEEK = 20; // u
27.256 + static final int PATTERN_ISO_ZONE = 21; // X
27.257 +
27.258 + /**
27.259 + * Localized date-time pattern characters. For example, a locale may
27.260 + * wish to use 'u' rather than 'y' to represent years in its date format
27.261 + * pattern strings.
27.262 + * This string must be exactly 18 characters long, with the index of
27.263 + * the characters described by <code>DateFormat.ERA_FIELD</code>,
27.264 + * <code>DateFormat.YEAR_FIELD</code>, etc. Thus, if the string were
27.265 + * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
27.266 + * @serial
27.267 + */
27.268 + String localPatternChars = null;
27.269 +
27.270 + /**
27.271 + * The locale which is used for initializing this DateFormatSymbols object.
27.272 + *
27.273 + * @since 1.6
27.274 + * @serial
27.275 + */
27.276 + Locale locale = null;
27.277 +
27.278 + /* use serialVersionUID from JDK 1.1.4 for interoperability */
27.279 + static final long serialVersionUID = -5987973545549424702L;
27.280 +
27.281 + /**
27.282 + * Returns an array of all locales for which the
27.283 + * <code>getInstance</code> methods of this class can return
27.284 + * localized instances.
27.285 + * The returned array represents the union of locales supported by the
27.286 + * Java runtime and by installed
27.287 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
27.288 + * implementations. It must contain at least a <code>Locale</code>
27.289 + * instance equal to {@link java.util.Locale#US Locale.US}.
27.290 + *
27.291 + * @return An array of locales for which localized
27.292 + * <code>DateFormatSymbols</code> instances are available.
27.293 + * @since 1.6
27.294 + */
27.295 + public static Locale[] getAvailableLocales() {
27.296 + LocaleServiceProviderPool pool=
27.297 + LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
27.298 + return pool.getAvailableLocales();
27.299 + }
27.300 +
27.301 + /**
27.302 + * Gets the <code>DateFormatSymbols</code> instance for the default
27.303 + * locale. This method provides access to <code>DateFormatSymbols</code>
27.304 + * instances for locales supported by the Java runtime itself as well
27.305 + * as for those supported by installed
27.306 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
27.307 + * implementations.
27.308 + * @return a <code>DateFormatSymbols</code> instance.
27.309 + * @since 1.6
27.310 + */
27.311 + public static final DateFormatSymbols getInstance() {
27.312 + return getInstance(Locale.getDefault(Locale.Category.FORMAT));
27.313 + }
27.314 +
27.315 + /**
27.316 + * Gets the <code>DateFormatSymbols</code> instance for the specified
27.317 + * locale. This method provides access to <code>DateFormatSymbols</code>
27.318 + * instances for locales supported by the Java runtime itself as well
27.319 + * as for those supported by installed
27.320 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
27.321 + * implementations.
27.322 + * @param locale the given locale.
27.323 + * @return a <code>DateFormatSymbols</code> instance.
27.324 + * @exception NullPointerException if <code>locale</code> is null
27.325 + * @since 1.6
27.326 + */
27.327 + public static final DateFormatSymbols getInstance(Locale locale) {
27.328 + DateFormatSymbols dfs = getProviderInstance(locale);
27.329 + if (dfs != null) {
27.330 + return dfs;
27.331 + }
27.332 + return (DateFormatSymbols) getCachedInstance(locale).clone();
27.333 + }
27.334 +
27.335 + /**
27.336 + * Returns a DateFormatSymbols provided by a provider or found in
27.337 + * the cache. Note that this method returns a cached instance,
27.338 + * not its clone. Therefore, the instance should never be given to
27.339 + * an application.
27.340 + */
27.341 + static final DateFormatSymbols getInstanceRef(Locale locale) {
27.342 + DateFormatSymbols dfs = getProviderInstance(locale);
27.343 + if (dfs != null) {
27.344 + return dfs;
27.345 + }
27.346 + return getCachedInstance(locale);
27.347 + }
27.348 +
27.349 + private static DateFormatSymbols getProviderInstance(Locale locale) {
27.350 + DateFormatSymbols providersInstance = null;
27.351 +
27.352 + // Check whether a provider can provide an implementation that's closer
27.353 + // to the requested locale than what the Java runtime itself can provide.
27.354 + LocaleServiceProviderPool pool =
27.355 + LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
27.356 + if (pool.hasProviders()) {
27.357 + providersInstance = pool.getLocalizedObject(
27.358 + DateFormatSymbolsGetter.INSTANCE, locale);
27.359 + }
27.360 + return providersInstance;
27.361 + }
27.362 +
27.363 + /**
27.364 + * Returns a cached DateFormatSymbols if it's found in the
27.365 + * cache. Otherwise, this method returns a newly cached instance
27.366 + * for the given locale.
27.367 + */
27.368 + private static DateFormatSymbols getCachedInstance(Locale locale) {
27.369 + SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
27.370 + DateFormatSymbols dfs = null;
27.371 + if (ref == null || (dfs = ref.get()) == null) {
27.372 + dfs = new DateFormatSymbols(locale);
27.373 + ref = new SoftReference<DateFormatSymbols>(dfs);
27.374 + SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
27.375 + if (x != null) {
27.376 + DateFormatSymbols y = x.get();
27.377 + if (y != null) {
27.378 + dfs = y;
27.379 + } else {
27.380 + // Replace the empty SoftReference with ref.
27.381 + cachedInstances.put(locale, ref);
27.382 + }
27.383 + }
27.384 + }
27.385 + return dfs;
27.386 + }
27.387 +
27.388 + /**
27.389 + * Gets era strings. For example: "AD" and "BC".
27.390 + * @return the era strings.
27.391 + */
27.392 + public String[] getEras() {
27.393 + return Arrays.copyOf(eras, eras.length);
27.394 + }
27.395 +
27.396 + /**
27.397 + * Sets era strings. For example: "AD" and "BC".
27.398 + * @param newEras the new era strings.
27.399 + */
27.400 + public void setEras(String[] newEras) {
27.401 + eras = Arrays.copyOf(newEras, newEras.length);
27.402 + }
27.403 +
27.404 + /**
27.405 + * Gets month strings. For example: "January", "February", etc.
27.406 + * @return the month strings.
27.407 + */
27.408 + public String[] getMonths() {
27.409 + return Arrays.copyOf(months, months.length);
27.410 + }
27.411 +
27.412 + /**
27.413 + * Sets month strings. For example: "January", "February", etc.
27.414 + * @param newMonths the new month strings.
27.415 + */
27.416 + public void setMonths(String[] newMonths) {
27.417 + months = Arrays.copyOf(newMonths, newMonths.length);
27.418 + }
27.419 +
27.420 + /**
27.421 + * Gets short month strings. For example: "Jan", "Feb", etc.
27.422 + * @return the short month strings.
27.423 + */
27.424 + public String[] getShortMonths() {
27.425 + return Arrays.copyOf(shortMonths, shortMonths.length);
27.426 + }
27.427 +
27.428 + /**
27.429 + * Sets short month strings. For example: "Jan", "Feb", etc.
27.430 + * @param newShortMonths the new short month strings.
27.431 + */
27.432 + public void setShortMonths(String[] newShortMonths) {
27.433 + shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
27.434 + }
27.435 +
27.436 + /**
27.437 + * Gets weekday strings. For example: "Sunday", "Monday", etc.
27.438 + * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
27.439 + * <code>Calendar.MONDAY</code>, etc. to index the result array.
27.440 + */
27.441 + public String[] getWeekdays() {
27.442 + return Arrays.copyOf(weekdays, weekdays.length);
27.443 + }
27.444 +
27.445 + /**
27.446 + * Sets weekday strings. For example: "Sunday", "Monday", etc.
27.447 + * @param newWeekdays the new weekday strings. The array should
27.448 + * be indexed by <code>Calendar.SUNDAY</code>,
27.449 + * <code>Calendar.MONDAY</code>, etc.
27.450 + */
27.451 + public void setWeekdays(String[] newWeekdays) {
27.452 + weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
27.453 + }
27.454 +
27.455 + /**
27.456 + * Gets short weekday strings. For example: "Sun", "Mon", etc.
27.457 + * @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
27.458 + * <code>Calendar.MONDAY</code>, etc. to index the result array.
27.459 + */
27.460 + public String[] getShortWeekdays() {
27.461 + return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
27.462 + }
27.463 +
27.464 + /**
27.465 + * Sets short weekday strings. For example: "Sun", "Mon", etc.
27.466 + * @param newShortWeekdays the new short weekday strings. The array should
27.467 + * be indexed by <code>Calendar.SUNDAY</code>,
27.468 + * <code>Calendar.MONDAY</code>, etc.
27.469 + */
27.470 + public void setShortWeekdays(String[] newShortWeekdays) {
27.471 + shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
27.472 + }
27.473 +
27.474 + /**
27.475 + * Gets ampm strings. For example: "AM" and "PM".
27.476 + * @return the ampm strings.
27.477 + */
27.478 + public String[] getAmPmStrings() {
27.479 + return Arrays.copyOf(ampms, ampms.length);
27.480 + }
27.481 +
27.482 + /**
27.483 + * Sets ampm strings. For example: "AM" and "PM".
27.484 + * @param newAmpms the new ampm strings.
27.485 + */
27.486 + public void setAmPmStrings(String[] newAmpms) {
27.487 + ampms = Arrays.copyOf(newAmpms, newAmpms.length);
27.488 + }
27.489 +
27.490 + /**
27.491 + * Gets time zone strings. Use of this method is discouraged; use
27.492 + * {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
27.493 + * instead.
27.494 + * <p>
27.495 + * The value returned is a
27.496 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
27.497 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
27.498 + * entry containing the localized names for a single <code>TimeZone</code>.
27.499 + * Each such row contains (with <code>i</code> ranging from
27.500 + * 0..<em>n</em>-1):
27.501 + * <ul>
27.502 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
27.503 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
27.504 + * time</li>
27.505 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
27.506 + * standard time</li>
27.507 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
27.508 + * saving time</li>
27.509 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
27.510 + * saving time</li>
27.511 + * </ul>
27.512 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
27.513 + * the {@link java.util.TimeZone TimeZone} class that are not
27.514 + * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
27.515 + * All other entries are localized names. If a zone does not implement
27.516 + * daylight saving time, the daylight saving time names should not be used.
27.517 + * <p>
27.518 + * If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
27.519 + * on this <code>DateFormatSymbols</code> instance, then the strings
27.520 + * provided by that call are returned. Otherwise, the returned array
27.521 + * contains names provided by the Java runtime and by installed
27.522 + * {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider}
27.523 + * implementations.
27.524 + *
27.525 + * @return the time zone strings.
27.526 + * @see #setZoneStrings(String[][])
27.527 + */
27.528 + public String[][] getZoneStrings() {
27.529 + return getZoneStringsImpl(true);
27.530 + }
27.531 +
27.532 + /**
27.533 + * Sets time zone strings. The argument must be a
27.534 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
27.535 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
27.536 + * entry containing the localized names for a single <code>TimeZone</code>.
27.537 + * Each such row contains (with <code>i</code> ranging from
27.538 + * 0..<em>n</em>-1):
27.539 + * <ul>
27.540 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
27.541 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
27.542 + * time</li>
27.543 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
27.544 + * standard time</li>
27.545 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
27.546 + * saving time</li>
27.547 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
27.548 + * saving time</li>
27.549 + * </ul>
27.550 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
27.551 + * the {@link java.util.TimeZone TimeZone} class that are not
27.552 + * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
27.553 + * All other entries are localized names.
27.554 + *
27.555 + * @param newZoneStrings the new time zone strings.
27.556 + * @exception IllegalArgumentException if the length of any row in
27.557 + * <code>newZoneStrings</code> is less than 5
27.558 + * @exception NullPointerException if <code>newZoneStrings</code> is null
27.559 + * @see #getZoneStrings()
27.560 + */
27.561 + public void setZoneStrings(String[][] newZoneStrings) {
27.562 + String[][] aCopy = new String[newZoneStrings.length][];
27.563 + for (int i = 0; i < newZoneStrings.length; ++i) {
27.564 + int len = newZoneStrings[i].length;
27.565 + if (len < 5) {
27.566 + throw new IllegalArgumentException();
27.567 + }
27.568 + aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
27.569 + }
27.570 + zoneStrings = aCopy;
27.571 + isZoneStringsSet = true;
27.572 + }
27.573 +
27.574 + /**
27.575 + * Gets localized date-time pattern characters. For example: 'u', 't', etc.
27.576 + * @return the localized date-time pattern characters.
27.577 + */
27.578 + public String getLocalPatternChars() {
27.579 + return localPatternChars;
27.580 + }
27.581 +
27.582 + /**
27.583 + * Sets localized date-time pattern characters. For example: 'u', 't', etc.
27.584 + * @param newLocalPatternChars the new localized date-time
27.585 + * pattern characters.
27.586 + */
27.587 + public void setLocalPatternChars(String newLocalPatternChars) {
27.588 + // Call toString() to throw an NPE in case the argument is null
27.589 + localPatternChars = newLocalPatternChars.toString();
27.590 + }
27.591 +
27.592 + /**
27.593 + * Overrides Cloneable
27.594 + */
27.595 + public Object clone()
27.596 + {
27.597 + try
27.598 + {
27.599 + DateFormatSymbols other = (DateFormatSymbols)super.clone();
27.600 + copyMembers(this, other);
27.601 + return other;
27.602 + } catch (CloneNotSupportedException e) {
27.603 + throw new InternalError();
27.604 + }
27.605 + }
27.606 +
27.607 + /**
27.608 + * Override hashCode.
27.609 + * Generates a hash code for the DateFormatSymbols object.
27.610 + */
27.611 + public int hashCode() {
27.612 + int hashcode = 0;
27.613 + String[][] zoneStrings = getZoneStringsWrapper();
27.614 + for (int index = 0; index < zoneStrings[0].length; ++index)
27.615 + hashcode ^= zoneStrings[0][index].hashCode();
27.616 + return hashcode;
27.617 + }
27.618 +
27.619 + /**
27.620 + * Override equals
27.621 + */
27.622 + public boolean equals(Object obj)
27.623 + {
27.624 + if (this == obj) return true;
27.625 + if (obj == null || getClass() != obj.getClass()) return false;
27.626 + DateFormatSymbols that = (DateFormatSymbols) obj;
27.627 + return (Arrays.equals(eras, that.eras)
27.628 + && Arrays.equals(months, that.months)
27.629 + && Arrays.equals(shortMonths, that.shortMonths)
27.630 + && Arrays.equals(weekdays, that.weekdays)
27.631 + && Arrays.equals(shortWeekdays, that.shortWeekdays)
27.632 + && Arrays.equals(ampms, that.ampms)
27.633 + && Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper())
27.634 + && ((localPatternChars != null
27.635 + && localPatternChars.equals(that.localPatternChars))
27.636 + || (localPatternChars == null
27.637 + && that.localPatternChars == null)));
27.638 + }
27.639 +
27.640 + // =======================privates===============================
27.641 +
27.642 + /**
27.643 + * Useful constant for defining time zone offsets.
27.644 + */
27.645 + static final int millisPerHour = 60*60*1000;
27.646 +
27.647 + /**
27.648 + * Cache to hold DateFormatSymbols instances per Locale.
27.649 + */
27.650 + private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
27.651 + = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
27.652 +
27.653 + private void initializeData(Locale desiredLocale) {
27.654 + locale = desiredLocale;
27.655 +
27.656 + // Copy values of a cached instance if any.
27.657 + SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
27.658 + DateFormatSymbols dfs;
27.659 + if (ref != null && (dfs = ref.get()) != null) {
27.660 + copyMembers(dfs, this);
27.661 + return;
27.662 + }
27.663 +
27.664 + // Initialize the fields from the ResourceBundle for locale.
27.665 + ResourceBundle resource = LocaleData.getDateFormatData(locale);
27.666 +
27.667 + eras = resource.getStringArray("Eras");
27.668 + months = resource.getStringArray("MonthNames");
27.669 + shortMonths = resource.getStringArray("MonthAbbreviations");
27.670 + ampms = resource.getStringArray("AmPmMarkers");
27.671 + localPatternChars = resource.getString("DateTimePatternChars");
27.672 +
27.673 + // Day of week names are stored in a 1-based array.
27.674 + weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
27.675 + shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
27.676 + }
27.677 +
27.678 + private static String[] toOneBasedArray(String[] src) {
27.679 + int len = src.length;
27.680 + String[] dst = new String[len + 1];
27.681 + dst[0] = "";
27.682 + for (int i = 0; i < len; i++) {
27.683 + dst[i + 1] = src[i];
27.684 + }
27.685 + return dst;
27.686 + }
27.687 +
27.688 + /**
27.689 + * Package private: used by SimpleDateFormat
27.690 + * Gets the index for the given time zone ID to obtain the time zone
27.691 + * strings for formatting. The time zone ID is just for programmatic
27.692 + * lookup. NOT LOCALIZED!!!
27.693 + * @param ID the given time zone ID.
27.694 + * @return the index of the given time zone ID. Returns -1 if
27.695 + * the given time zone ID can't be located in the DateFormatSymbols object.
27.696 + * @see java.util.SimpleTimeZone
27.697 + */
27.698 + final int getZoneIndex(String ID)
27.699 + {
27.700 + String[][] zoneStrings = getZoneStringsWrapper();
27.701 + for (int index=0; index<zoneStrings.length; index++)
27.702 + {
27.703 + if (ID.equals(zoneStrings[index][0])) return index;
27.704 + }
27.705 +
27.706 + return -1;
27.707 + }
27.708 +
27.709 + /**
27.710 + * Wrapper method to the getZoneStrings(), which is called from inside
27.711 + * the java.text package and not to mutate the returned arrays, so that
27.712 + * it does not need to create a defensive copy.
27.713 + */
27.714 + final String[][] getZoneStringsWrapper() {
27.715 + if (isSubclassObject()) {
27.716 + return getZoneStrings();
27.717 + } else {
27.718 + return getZoneStringsImpl(false);
27.719 + }
27.720 + }
27.721 +
27.722 + private final String[][] getZoneStringsImpl(boolean needsCopy) {
27.723 + if (zoneStrings == null) {
27.724 + zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
27.725 + }
27.726 +
27.727 + if (!needsCopy) {
27.728 + return zoneStrings;
27.729 + }
27.730 +
27.731 + int len = zoneStrings.length;
27.732 + String[][] aCopy = new String[len][];
27.733 + for (int i = 0; i < len; i++) {
27.734 + aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
27.735 + }
27.736 + return aCopy;
27.737 + }
27.738 +
27.739 + private final boolean isSubclassObject() {
27.740 + return !getClass().getName().equals("java.text.DateFormatSymbols");
27.741 + }
27.742 +
27.743 + /**
27.744 + * Clones all the data members from the source DateFormatSymbols to
27.745 + * the target DateFormatSymbols. This is only for subclasses.
27.746 + * @param src the source DateFormatSymbols.
27.747 + * @param dst the target DateFormatSymbols.
27.748 + */
27.749 + private final void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
27.750 + {
27.751 + dst.eras = Arrays.copyOf(src.eras, src.eras.length);
27.752 + dst.months = Arrays.copyOf(src.months, src.months.length);
27.753 + dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
27.754 + dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
27.755 + dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
27.756 + dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
27.757 + if (src.zoneStrings != null) {
27.758 + dst.zoneStrings = src.getZoneStringsImpl(true);
27.759 + } else {
27.760 + dst.zoneStrings = null;
27.761 + }
27.762 + dst.localPatternChars = src.localPatternChars;
27.763 + }
27.764 +
27.765 + /**
27.766 + * Write out the default serializable data, after ensuring the
27.767 + * <code>zoneStrings</code> field is initialized in order to make
27.768 + * sure the backward compatibility.
27.769 + *
27.770 + * @since 1.6
27.771 + */
27.772 + private void writeObject(ObjectOutputStream stream) throws IOException {
27.773 + if (zoneStrings == null) {
27.774 + zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
27.775 + }
27.776 + stream.defaultWriteObject();
27.777 + }
27.778 +
27.779 + /**
27.780 + * Obtains a DateFormatSymbols instance from a DateFormatSymbolsProvider
27.781 + * implementation.
27.782 + */
27.783 + private static class DateFormatSymbolsGetter
27.784 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatSymbolsProvider,
27.785 + DateFormatSymbols> {
27.786 + private static final DateFormatSymbolsGetter INSTANCE =
27.787 + new DateFormatSymbolsGetter();
27.788 +
27.789 + public DateFormatSymbols getObject(DateFormatSymbolsProvider dateFormatSymbolsProvider,
27.790 + Locale locale,
27.791 + String key,
27.792 + Object... params) {
27.793 + assert params.length == 0;
27.794 + return dateFormatSymbolsProvider.getInstance(locale);
27.795 + }
27.796 + }
27.797 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormat.java Thu Oct 03 15:40:35 2013 +0200
28.3 @@ -0,0 +1,3278 @@
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, 1997 - All Rights Reserved
28.31 + * (C) Copyright IBM Corp. 1996 - 1998 - 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.io.IOException;
28.46 +import java.io.ObjectInputStream;
28.47 +import java.math.BigDecimal;
28.48 +import java.math.BigInteger;
28.49 +import java.math.RoundingMode;
28.50 +import java.util.ArrayList;
28.51 +import java.util.Currency;
28.52 +import java.util.Locale;
28.53 +import java.util.ResourceBundle;
28.54 +import java.util.concurrent.ConcurrentHashMap;
28.55 +import java.util.concurrent.ConcurrentMap;
28.56 +import java.util.concurrent.atomic.AtomicInteger;
28.57 +import java.util.concurrent.atomic.AtomicLong;
28.58 +import sun.util.resources.LocaleData;
28.59 +
28.60 +/**
28.61 + * <code>DecimalFormat</code> is a concrete subclass of
28.62 + * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
28.63 + * features designed to make it possible to parse and format numbers in any
28.64 + * locale, including support for Western, Arabic, and Indic digits. It also
28.65 + * supports different kinds of numbers, including integers (123), fixed-point
28.66 + * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
28.67 + * currency amounts ($123). All of these can be localized.
28.68 + *
28.69 + * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
28.70 + * default locale, call one of <code>NumberFormat</code>'s factory methods, such
28.71 + * as <code>getInstance()</code>. In general, do not call the
28.72 + * <code>DecimalFormat</code> constructors directly, since the
28.73 + * <code>NumberFormat</code> factory methods may return subclasses other than
28.74 + * <code>DecimalFormat</code>. If you need to customize the format object, do
28.75 + * something like this:
28.76 + *
28.77 + * <blockquote><pre>
28.78 + * NumberFormat f = NumberFormat.getInstance(loc);
28.79 + * if (f instanceof DecimalFormat) {
28.80 + * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
28.81 + * }
28.82 + * </pre></blockquote>
28.83 + *
28.84 + * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
28.85 + * <em>symbols</em>. The pattern may be set directly using
28.86 + * <code>applyPattern()</code>, or indirectly using the API methods. The
28.87 + * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using
28.88 + * the <code>NumberFormat</code> factory methods, the pattern and symbols are
28.89 + * read from localized <code>ResourceBundle</code>s.
28.90 + *
28.91 + * <h4>Patterns</h4>
28.92 + *
28.93 + * <code>DecimalFormat</code> patterns have the following syntax:
28.94 + * <blockquote><pre>
28.95 + * <i>Pattern:</i>
28.96 + * <i>PositivePattern</i>
28.97 + * <i>PositivePattern</i> ; <i>NegativePattern</i>
28.98 + * <i>PositivePattern:</i>
28.99 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
28.100 + * <i>NegativePattern:</i>
28.101 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
28.102 + * <i>Prefix:</i>
28.103 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
28.104 + * <i>Suffix:</i>
28.105 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
28.106 + * <i>Number:</i>
28.107 + * <i>Integer</i> <i>Exponent<sub>opt</sub></i>
28.108 + * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
28.109 + * <i>Integer:</i>
28.110 + * <i>MinimumInteger</i>
28.111 + * #
28.112 + * # <i>Integer</i>
28.113 + * # , <i>Integer</i>
28.114 + * <i>MinimumInteger:</i>
28.115 + * 0
28.116 + * 0 <i>MinimumInteger</i>
28.117 + * 0 , <i>MinimumInteger</i>
28.118 + * <i>Fraction:</i>
28.119 + * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
28.120 + * <i>MinimumFraction:</i>
28.121 + * 0 <i>MinimumFraction<sub>opt</sub></i>
28.122 + * <i>OptionalFraction:</i>
28.123 + * # <i>OptionalFraction<sub>opt</sub></i>
28.124 + * <i>Exponent:</i>
28.125 + * E <i>MinimumExponent</i>
28.126 + * <i>MinimumExponent:</i>
28.127 + * 0 <i>MinimumExponent<sub>opt</sub></i>
28.128 + * </pre></blockquote>
28.129 + *
28.130 + * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
28.131 + * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each
28.132 + * subpattern has a prefix, numeric part, and suffix. The negative subpattern
28.133 + * is optional; if absent, then the positive subpattern prefixed with the
28.134 + * localized minus sign (<code>'-'</code> in most locales) is used as the
28.135 + * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
28.136 + * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it
28.137 + * serves only to specify the negative prefix and suffix; the number of digits,
28.138 + * minimal digits, and other characteristics are all the same as the positive
28.139 + * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
28.140 + * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
28.141 + *
28.142 + * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
28.143 + * thousands separators, decimal separators, etc. may be set to arbitrary
28.144 + * values, and they will appear properly during formatting. However, care must
28.145 + * be taken that the symbols and strings do not conflict, or parsing will be
28.146 + * unreliable. For example, either the positive and negative prefixes or the
28.147 + * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
28.148 + * to distinguish positive from negative values. (If they are identical, then
28.149 + * <code>DecimalFormat</code> will behave as if no negative subpattern was
28.150 + * specified.) Another example is that the decimal separator and thousands
28.151 + * separator should be distinct characters, or parsing will be impossible.
28.152 + *
28.153 + * <p>The grouping separator is commonly used for thousands, but in some
28.154 + * countries it separates ten-thousands. The grouping size is a constant number
28.155 + * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
28.156 + * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
28.157 + * interval between the last one and the end of the integer is the one that is
28.158 + * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
28.159 + * <code>"##,####,####"</code>.
28.160 + *
28.161 + * <h4>Special Pattern Characters</h4>
28.162 + *
28.163 + * <p>Many characters in a pattern are taken literally; they are matched during
28.164 + * parsing and output unchanged during formatting. Special characters, on the
28.165 + * other hand, stand for other characters, strings, or classes of characters.
28.166 + * They must be quoted, unless noted otherwise, if they are to appear in the
28.167 + * prefix or suffix as literals.
28.168 + *
28.169 + * <p>The characters listed here are used in non-localized patterns. Localized
28.170 + * patterns use the corresponding characters taken from this formatter's
28.171 + * <code>DecimalFormatSymbols</code> object instead, and these characters lose
28.172 + * their special status. Two exceptions are the currency sign and quote, which
28.173 + * are not localized.
28.174 + *
28.175 + * <blockquote>
28.176 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
28.177 + * location, localized, and meaning.">
28.178 + * <tr bgcolor="#ccccff">
28.179 + * <th align=left>Symbol
28.180 + * <th align=left>Location
28.181 + * <th align=left>Localized?
28.182 + * <th align=left>Meaning
28.183 + * <tr valign=top>
28.184 + * <td><code>0</code>
28.185 + * <td>Number
28.186 + * <td>Yes
28.187 + * <td>Digit
28.188 + * <tr valign=top bgcolor="#eeeeff">
28.189 + * <td><code>#</code>
28.190 + * <td>Number
28.191 + * <td>Yes
28.192 + * <td>Digit, zero shows as absent
28.193 + * <tr valign=top>
28.194 + * <td><code>.</code>
28.195 + * <td>Number
28.196 + * <td>Yes
28.197 + * <td>Decimal separator or monetary decimal separator
28.198 + * <tr valign=top bgcolor="#eeeeff">
28.199 + * <td><code>-</code>
28.200 + * <td>Number
28.201 + * <td>Yes
28.202 + * <td>Minus sign
28.203 + * <tr valign=top>
28.204 + * <td><code>,</code>
28.205 + * <td>Number
28.206 + * <td>Yes
28.207 + * <td>Grouping separator
28.208 + * <tr valign=top bgcolor="#eeeeff">
28.209 + * <td><code>E</code>
28.210 + * <td>Number
28.211 + * <td>Yes
28.212 + * <td>Separates mantissa and exponent in scientific notation.
28.213 + * <em>Need not be quoted in prefix or suffix.</em>
28.214 + * <tr valign=top>
28.215 + * <td><code>;</code>
28.216 + * <td>Subpattern boundary
28.217 + * <td>Yes
28.218 + * <td>Separates positive and negative subpatterns
28.219 + * <tr valign=top bgcolor="#eeeeff">
28.220 + * <td><code>%</code>
28.221 + * <td>Prefix or suffix
28.222 + * <td>Yes
28.223 + * <td>Multiply by 100 and show as percentage
28.224 + * <tr valign=top>
28.225 + * <td><code>\u2030</code>
28.226 + * <td>Prefix or suffix
28.227 + * <td>Yes
28.228 + * <td>Multiply by 1000 and show as per mille value
28.229 + * <tr valign=top bgcolor="#eeeeff">
28.230 + * <td><code>¤</code> (<code>\u00A4</code>)
28.231 + * <td>Prefix or suffix
28.232 + * <td>No
28.233 + * <td>Currency sign, replaced by currency symbol. If
28.234 + * doubled, replaced by international currency symbol.
28.235 + * If present in a pattern, the monetary decimal separator
28.236 + * is used instead of the decimal separator.
28.237 + * <tr valign=top>
28.238 + * <td><code>'</code>
28.239 + * <td>Prefix or suffix
28.240 + * <td>No
28.241 + * <td>Used to quote special characters in a prefix or suffix,
28.242 + * for example, <code>"'#'#"</code> formats 123 to
28.243 + * <code>"#123"</code>. To create a single quote
28.244 + * itself, use two in a row: <code>"# o''clock"</code>.
28.245 + * </table>
28.246 + * </blockquote>
28.247 + *
28.248 + * <h4>Scientific Notation</h4>
28.249 + *
28.250 + * <p>Numbers in scientific notation are expressed as the product of a mantissa
28.251 + * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The
28.252 + * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
28.253 + * <code>DecimalFormat</code> can be instructed to format and parse scientific
28.254 + * notation <em>only via a pattern</em>; there is currently no factory method
28.255 + * that creates a scientific notation format. In a pattern, the exponent
28.256 + * character immediately followed by one or more digit characters indicates
28.257 + * scientific notation. Example: <code>"0.###E0"</code> formats the number
28.258 + * 1234 as <code>"1.234E3"</code>.
28.259 + *
28.260 + * <ul>
28.261 + * <li>The number of digit characters after the exponent character gives the
28.262 + * minimum exponent digit count. There is no maximum. Negative exponents are
28.263 + * formatted using the localized minus sign, <em>not</em> the prefix and suffix
28.264 + * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>.
28.265 + *
28.266 + * <li>The minimum and maximum number of integer digits are interpreted
28.267 + * together:
28.268 + *
28.269 + * <ul>
28.270 + * <li>If the maximum number of integer digits is greater than their minimum number
28.271 + * and greater than 1, it forces the exponent to be a multiple of the maximum
28.272 + * number of integer digits, and the minimum number of integer digits to be
28.273 + * interpreted as 1. The most common use of this is to generate
28.274 + * <em>engineering notation</em>, in which the exponent is a multiple of three,
28.275 + * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
28.276 + * formats to <code>"12.345E3"</code>, and 123456 formats to
28.277 + * <code>"123.456E3"</code>.
28.278 + *
28.279 + * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
28.280 + * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields
28.281 + * <code>"12.3E-4"</code>.
28.282 + * </ul>
28.283 + *
28.284 + * <li>The number of significant digits in the mantissa is the sum of the
28.285 + * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
28.286 + * unaffected by the maximum integer digits. For example, 12345 formatted with
28.287 + * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
28.288 + * the significant digits count to zero. The number of significant digits
28.289 + * does not affect parsing.
28.290 + *
28.291 + * <li>Exponential patterns may not contain grouping separators.
28.292 + * </ul>
28.293 + *
28.294 + * <h4>Rounding</h4>
28.295 + *
28.296 + * <code>DecimalFormat</code> provides rounding modes defined in
28.297 + * {@link java.math.RoundingMode} for formatting. By default, it uses
28.298 + * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
28.299 + *
28.300 + * <h4>Digits</h4>
28.301 + *
28.302 + * For formatting, <code>DecimalFormat</code> uses the ten consecutive
28.303 + * characters starting with the localized zero digit defined in the
28.304 + * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
28.305 + * digits as well as all Unicode decimal digits, as defined by
28.306 + * {@link Character#digit Character.digit}, are recognized.
28.307 + *
28.308 + * <h4>Special Values</h4>
28.309 + *
28.310 + * <p><code>NaN</code> is formatted as a string, which typically has a single character
28.311 + * <code>\uFFFD</code>. This string is determined by the
28.312 + * <code>DecimalFormatSymbols</code> object. This is the only value for which
28.313 + * the prefixes and suffixes are not used.
28.314 + *
28.315 + * <p>Infinity is formatted as a string, which typically has a single character
28.316 + * <code>\u221E</code>, with the positive or negative prefixes and suffixes
28.317 + * applied. The infinity string is determined by the
28.318 + * <code>DecimalFormatSymbols</code> object.
28.319 + *
28.320 + * <p>Negative zero (<code>"-0"</code>) parses to
28.321 + * <ul>
28.322 + * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
28.323 + * true,
28.324 + * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
28.325 + * and <code>isParseIntegerOnly()</code> is true,
28.326 + * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
28.327 + * and <code>isParseIntegerOnly()</code> are false.
28.328 + * </ul>
28.329 + *
28.330 + * <h4><a name="synchronization">Synchronization</a></h4>
28.331 + *
28.332 + * <p>
28.333 + * Decimal formats are generally not synchronized.
28.334 + * It is recommended to create separate format instances for each thread.
28.335 + * If multiple threads access a format concurrently, it must be synchronized
28.336 + * externally.
28.337 + *
28.338 + * <h4>Example</h4>
28.339 + *
28.340 + * <blockquote><pre>
28.341 + * <strong>// Print out a number using the localized number, integer, currency,
28.342 + * // and percent format for each locale</strong>
28.343 + * Locale[] locales = NumberFormat.getAvailableLocales();
28.344 + * double myNumber = -1234.56;
28.345 + * NumberFormat form;
28.346 + * for (int j=0; j<4; ++j) {
28.347 + * System.out.println("FORMAT");
28.348 + * for (int i = 0; i < locales.length; ++i) {
28.349 + * if (locales[i].getCountry().length() == 0) {
28.350 + * continue; // Skip language-only locales
28.351 + * }
28.352 + * System.out.print(locales[i].getDisplayName());
28.353 + * switch (j) {
28.354 + * case 0:
28.355 + * form = NumberFormat.getInstance(locales[i]); break;
28.356 + * case 1:
28.357 + * form = NumberFormat.getIntegerInstance(locales[i]); break;
28.358 + * case 2:
28.359 + * form = NumberFormat.getCurrencyInstance(locales[i]); break;
28.360 + * default:
28.361 + * form = NumberFormat.getPercentInstance(locales[i]); break;
28.362 + * }
28.363 + * if (form instanceof DecimalFormat) {
28.364 + * System.out.print(": " + ((DecimalFormat) form).toPattern());
28.365 + * }
28.366 + * System.out.print(" -> " + form.format(myNumber));
28.367 + * try {
28.368 + * System.out.println(" -> " + form.parse(form.format(myNumber)));
28.369 + * } catch (ParseException e) {}
28.370 + * }
28.371 + * }
28.372 + * </pre></blockquote>
28.373 + *
28.374 + * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
28.375 + * @see NumberFormat
28.376 + * @see DecimalFormatSymbols
28.377 + * @see ParsePosition
28.378 + * @author Mark Davis
28.379 + * @author Alan Liu
28.380 + */
28.381 +public class DecimalFormat extends NumberFormat {
28.382 +
28.383 + /**
28.384 + * Creates a DecimalFormat using the default pattern and symbols
28.385 + * for the default locale. This is a convenient way to obtain a
28.386 + * DecimalFormat when internationalization is not the main concern.
28.387 + * <p>
28.388 + * To obtain standard formats for a given locale, use the factory methods
28.389 + * on NumberFormat such as getNumberInstance. These factories will
28.390 + * return the most appropriate sub-class of NumberFormat for a given
28.391 + * locale.
28.392 + *
28.393 + * @see java.text.NumberFormat#getInstance
28.394 + * @see java.text.NumberFormat#getNumberInstance
28.395 + * @see java.text.NumberFormat#getCurrencyInstance
28.396 + * @see java.text.NumberFormat#getPercentInstance
28.397 + */
28.398 + public DecimalFormat() {
28.399 + Locale def = Locale.getDefault(Locale.Category.FORMAT);
28.400 + // try to get the pattern from the cache
28.401 + String pattern = cachedLocaleData.get(def);
28.402 + if (pattern == null) { /* cache miss */
28.403 + // Get the pattern for the default locale.
28.404 + ResourceBundle rb = LocaleData.getNumberFormatData(def);
28.405 + String[] all = rb.getStringArray("NumberPatterns");
28.406 + pattern = all[0];
28.407 + /* update cache */
28.408 + cachedLocaleData.putIfAbsent(def, pattern);
28.409 + }
28.410 +
28.411 + // Always applyPattern after the symbols are set
28.412 + this.symbols = new DecimalFormatSymbols(def);
28.413 + applyPattern(pattern, false);
28.414 + }
28.415 +
28.416 +
28.417 + /**
28.418 + * Creates a DecimalFormat using the given pattern and the symbols
28.419 + * for the default locale. This is a convenient way to obtain a
28.420 + * DecimalFormat when internationalization is not the main concern.
28.421 + * <p>
28.422 + * To obtain standard formats for a given locale, use the factory methods
28.423 + * on NumberFormat such as getNumberInstance. These factories will
28.424 + * return the most appropriate sub-class of NumberFormat for a given
28.425 + * locale.
28.426 + *
28.427 + * @param pattern A non-localized pattern string.
28.428 + * @exception NullPointerException if <code>pattern</code> is null
28.429 + * @exception IllegalArgumentException if the given pattern is invalid.
28.430 + * @see java.text.NumberFormat#getInstance
28.431 + * @see java.text.NumberFormat#getNumberInstance
28.432 + * @see java.text.NumberFormat#getCurrencyInstance
28.433 + * @see java.text.NumberFormat#getPercentInstance
28.434 + */
28.435 + public DecimalFormat(String pattern) {
28.436 + // Always applyPattern after the symbols are set
28.437 + this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
28.438 + applyPattern(pattern, false);
28.439 + }
28.440 +
28.441 +
28.442 + /**
28.443 + * Creates a DecimalFormat using the given pattern and symbols.
28.444 + * Use this constructor when you need to completely customize the
28.445 + * behavior of the format.
28.446 + * <p>
28.447 + * To obtain standard formats for a given
28.448 + * locale, use the factory methods on NumberFormat such as
28.449 + * getInstance or getCurrencyInstance. If you need only minor adjustments
28.450 + * to a standard format, you can modify the format returned by
28.451 + * a NumberFormat factory method.
28.452 + *
28.453 + * @param pattern a non-localized pattern string
28.454 + * @param symbols the set of symbols to be used
28.455 + * @exception NullPointerException if any of the given arguments is null
28.456 + * @exception IllegalArgumentException if the given pattern is invalid
28.457 + * @see java.text.NumberFormat#getInstance
28.458 + * @see java.text.NumberFormat#getNumberInstance
28.459 + * @see java.text.NumberFormat#getCurrencyInstance
28.460 + * @see java.text.NumberFormat#getPercentInstance
28.461 + * @see java.text.DecimalFormatSymbols
28.462 + */
28.463 + public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
28.464 + // Always applyPattern after the symbols are set
28.465 + this.symbols = (DecimalFormatSymbols)symbols.clone();
28.466 + applyPattern(pattern, false);
28.467 + }
28.468 +
28.469 +
28.470 + // Overrides
28.471 + /**
28.472 + * Formats a number and appends the resulting text to the given string
28.473 + * buffer.
28.474 + * The number can be of any subclass of {@link java.lang.Number}.
28.475 + * <p>
28.476 + * This implementation uses the maximum precision permitted.
28.477 + * @param number the number to format
28.478 + * @param toAppendTo the <code>StringBuffer</code> to which the formatted
28.479 + * text is to be appended
28.480 + * @param pos On input: an alignment field, if desired.
28.481 + * On output: the offsets of the alignment field.
28.482 + * @return the value passed in as <code>toAppendTo</code>
28.483 + * @exception IllegalArgumentException if <code>number</code> is
28.484 + * null or not an instance of <code>Number</code>.
28.485 + * @exception NullPointerException if <code>toAppendTo</code> or
28.486 + * <code>pos</code> is null
28.487 + * @exception ArithmeticException if rounding is needed with rounding
28.488 + * mode being set to RoundingMode.UNNECESSARY
28.489 + * @see java.text.FieldPosition
28.490 + */
28.491 + public final StringBuffer format(Object number,
28.492 + StringBuffer toAppendTo,
28.493 + FieldPosition pos) {
28.494 + if (number instanceof Long || number instanceof Integer ||
28.495 + number instanceof Short || number instanceof Byte ||
28.496 + number instanceof AtomicInteger ||
28.497 + number instanceof AtomicLong ||
28.498 + (number instanceof BigInteger &&
28.499 + ((BigInteger)number).bitLength () < 64)) {
28.500 + return format(((Number)number).longValue(), toAppendTo, pos);
28.501 + } else if (number instanceof BigDecimal) {
28.502 + return format((BigDecimal)number, toAppendTo, pos);
28.503 + } else if (number instanceof BigInteger) {
28.504 + return format((BigInteger)number, toAppendTo, pos);
28.505 + } else if (number instanceof Number) {
28.506 + return format(((Number)number).doubleValue(), toAppendTo, pos);
28.507 + } else {
28.508 + throw new IllegalArgumentException("Cannot format given Object as a Number");
28.509 + }
28.510 + }
28.511 +
28.512 + /**
28.513 + * Formats a double to produce a string.
28.514 + * @param number The double to format
28.515 + * @param result where the text is to be appended
28.516 + * @param fieldPosition On input: an alignment field, if desired.
28.517 + * On output: the offsets of the alignment field.
28.518 + * @exception ArithmeticException if rounding is needed with rounding
28.519 + * mode being set to RoundingMode.UNNECESSARY
28.520 + * @return The formatted number string
28.521 + * @see java.text.FieldPosition
28.522 + */
28.523 + public StringBuffer format(double number, StringBuffer result,
28.524 + FieldPosition fieldPosition) {
28.525 + fieldPosition.setBeginIndex(0);
28.526 + fieldPosition.setEndIndex(0);
28.527 +
28.528 + return format(number, result, fieldPosition.getFieldDelegate());
28.529 + }
28.530 +
28.531 + /**
28.532 + * Formats a double to produce a string.
28.533 + * @param number The double to format
28.534 + * @param result where the text is to be appended
28.535 + * @param delegate notified of locations of sub fields
28.536 + * @exception ArithmeticException if rounding is needed with rounding
28.537 + * mode being set to RoundingMode.UNNECESSARY
28.538 + * @return The formatted number string
28.539 + */
28.540 + private StringBuffer format(double number, StringBuffer result,
28.541 + FieldDelegate delegate) {
28.542 + if (Double.isNaN(number) ||
28.543 + (Double.isInfinite(number) && multiplier == 0)) {
28.544 + int iFieldStart = result.length();
28.545 + result.append(symbols.getNaN());
28.546 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
28.547 + iFieldStart, result.length(), result);
28.548 + return result;
28.549 + }
28.550 +
28.551 + /* Detecting whether a double is negative is easy with the exception of
28.552 + * the value -0.0. This is a double which has a zero mantissa (and
28.553 + * exponent), but a negative sign bit. It is semantically distinct from
28.554 + * a zero with a positive sign bit, and this distinction is important
28.555 + * to certain kinds of computations. However, it's a little tricky to
28.556 + * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
28.557 + * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
28.558 + * -Infinity. Proper detection of -0.0 is needed to deal with the
28.559 + * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
28.560 + */
28.561 + boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
28.562 +
28.563 + if (multiplier != 1) {
28.564 + number *= multiplier;
28.565 + }
28.566 +
28.567 + if (Double.isInfinite(number)) {
28.568 + if (isNegative) {
28.569 + append(result, negativePrefix, delegate,
28.570 + getNegativePrefixFieldPositions(), Field.SIGN);
28.571 + } else {
28.572 + append(result, positivePrefix, delegate,
28.573 + getPositivePrefixFieldPositions(), Field.SIGN);
28.574 + }
28.575 +
28.576 + int iFieldStart = result.length();
28.577 + result.append(symbols.getInfinity());
28.578 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
28.579 + iFieldStart, result.length(), result);
28.580 +
28.581 + if (isNegative) {
28.582 + append(result, negativeSuffix, delegate,
28.583 + getNegativeSuffixFieldPositions(), Field.SIGN);
28.584 + } else {
28.585 + append(result, positiveSuffix, delegate,
28.586 + getPositiveSuffixFieldPositions(), Field.SIGN);
28.587 + }
28.588 +
28.589 + return result;
28.590 + }
28.591 +
28.592 + if (isNegative) {
28.593 + number = -number;
28.594 + }
28.595 +
28.596 + // at this point we are guaranteed a nonnegative finite number.
28.597 + assert(number >= 0 && !Double.isInfinite(number));
28.598 +
28.599 + synchronized(digitList) {
28.600 + int maxIntDigits = super.getMaximumIntegerDigits();
28.601 + int minIntDigits = super.getMinimumIntegerDigits();
28.602 + int maxFraDigits = super.getMaximumFractionDigits();
28.603 + int minFraDigits = super.getMinimumFractionDigits();
28.604 +
28.605 + digitList.set(isNegative, number, useExponentialNotation ?
28.606 + maxIntDigits + maxFraDigits : maxFraDigits,
28.607 + !useExponentialNotation);
28.608 + return subformat(result, delegate, isNegative, false,
28.609 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
28.610 + }
28.611 + }
28.612 +
28.613 + /**
28.614 + * Format a long to produce a string.
28.615 + * @param number The long to format
28.616 + * @param result where the text is to be appended
28.617 + * @param fieldPosition On input: an alignment field, if desired.
28.618 + * On output: the offsets of the alignment field.
28.619 + * @exception ArithmeticException if rounding is needed with rounding
28.620 + * mode being set to RoundingMode.UNNECESSARY
28.621 + * @return The formatted number string
28.622 + * @see java.text.FieldPosition
28.623 + */
28.624 + public StringBuffer format(long number, StringBuffer result,
28.625 + FieldPosition fieldPosition) {
28.626 + fieldPosition.setBeginIndex(0);
28.627 + fieldPosition.setEndIndex(0);
28.628 +
28.629 + return format(number, result, fieldPosition.getFieldDelegate());
28.630 + }
28.631 +
28.632 + /**
28.633 + * Format a long to produce a string.
28.634 + * @param number The long to format
28.635 + * @param result where the text is to be appended
28.636 + * @param delegate notified of locations of sub fields
28.637 + * @return The formatted number string
28.638 + * @exception ArithmeticException if rounding is needed with rounding
28.639 + * mode being set to RoundingMode.UNNECESSARY
28.640 + * @see java.text.FieldPosition
28.641 + */
28.642 + private StringBuffer format(long number, StringBuffer result,
28.643 + FieldDelegate delegate) {
28.644 + boolean isNegative = (number < 0);
28.645 + if (isNegative) {
28.646 + number = -number;
28.647 + }
28.648 +
28.649 + // In general, long values always represent real finite numbers, so
28.650 + // we don't have to check for +/- Infinity or NaN. However, there
28.651 + // is one case we have to be careful of: The multiplier can push
28.652 + // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
28.653 + // check for this before multiplying, and if it happens we use
28.654 + // BigInteger instead.
28.655 + boolean useBigInteger = false;
28.656 + if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
28.657 + if (multiplier != 0) {
28.658 + useBigInteger = true;
28.659 + }
28.660 + } else if (multiplier != 1 && multiplier != 0) {
28.661 + long cutoff = Long.MAX_VALUE / multiplier;
28.662 + if (cutoff < 0) {
28.663 + cutoff = -cutoff;
28.664 + }
28.665 + useBigInteger = (number > cutoff);
28.666 + }
28.667 +
28.668 + if (useBigInteger) {
28.669 + if (isNegative) {
28.670 + number = -number;
28.671 + }
28.672 + BigInteger bigIntegerValue = BigInteger.valueOf(number);
28.673 + return format(bigIntegerValue, result, delegate, true);
28.674 + }
28.675 +
28.676 + number *= multiplier;
28.677 + if (number == 0) {
28.678 + isNegative = false;
28.679 + } else {
28.680 + if (multiplier < 0) {
28.681 + number = -number;
28.682 + isNegative = !isNegative;
28.683 + }
28.684 + }
28.685 +
28.686 + synchronized(digitList) {
28.687 + int maxIntDigits = super.getMaximumIntegerDigits();
28.688 + int minIntDigits = super.getMinimumIntegerDigits();
28.689 + int maxFraDigits = super.getMaximumFractionDigits();
28.690 + int minFraDigits = super.getMinimumFractionDigits();
28.691 +
28.692 + digitList.set(isNegative, number,
28.693 + useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
28.694 +
28.695 + return subformat(result, delegate, isNegative, true,
28.696 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
28.697 + }
28.698 + }
28.699 +
28.700 + /**
28.701 + * Formats a BigDecimal to produce a string.
28.702 + * @param number The BigDecimal to format
28.703 + * @param result where the text is to be appended
28.704 + * @param fieldPosition On input: an alignment field, if desired.
28.705 + * On output: the offsets of the alignment field.
28.706 + * @return The formatted number string
28.707 + * @exception ArithmeticException if rounding is needed with rounding
28.708 + * mode being set to RoundingMode.UNNECESSARY
28.709 + * @see java.text.FieldPosition
28.710 + */
28.711 + private StringBuffer format(BigDecimal number, StringBuffer result,
28.712 + FieldPosition fieldPosition) {
28.713 + fieldPosition.setBeginIndex(0);
28.714 + fieldPosition.setEndIndex(0);
28.715 + return format(number, result, fieldPosition.getFieldDelegate());
28.716 + }
28.717 +
28.718 + /**
28.719 + * Formats a BigDecimal to produce a string.
28.720 + * @param number The BigDecimal to format
28.721 + * @param result where the text is to be appended
28.722 + * @param delegate notified of locations of sub fields
28.723 + * @exception ArithmeticException if rounding is needed with rounding
28.724 + * mode being set to RoundingMode.UNNECESSARY
28.725 + * @return The formatted number string
28.726 + */
28.727 + private StringBuffer format(BigDecimal number, StringBuffer result,
28.728 + FieldDelegate delegate) {
28.729 + if (multiplier != 1) {
28.730 + number = number.multiply(getBigDecimalMultiplier());
28.731 + }
28.732 + boolean isNegative = number.signum() == -1;
28.733 + if (isNegative) {
28.734 + number = number.negate();
28.735 + }
28.736 +
28.737 + synchronized(digitList) {
28.738 + int maxIntDigits = getMaximumIntegerDigits();
28.739 + int minIntDigits = getMinimumIntegerDigits();
28.740 + int maxFraDigits = getMaximumFractionDigits();
28.741 + int minFraDigits = getMinimumFractionDigits();
28.742 + int maximumDigits = maxIntDigits + maxFraDigits;
28.743 +
28.744 + digitList.set(isNegative, number, useExponentialNotation ?
28.745 + ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
28.746 + maxFraDigits, !useExponentialNotation);
28.747 +
28.748 + return subformat(result, delegate, isNegative, false,
28.749 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
28.750 + }
28.751 + }
28.752 +
28.753 + /**
28.754 + * Format a BigInteger to produce a string.
28.755 + * @param number The BigInteger to format
28.756 + * @param result where the text is to be appended
28.757 + * @param fieldPosition On input: an alignment field, if desired.
28.758 + * On output: the offsets of the alignment field.
28.759 + * @return The formatted number string
28.760 + * @exception ArithmeticException if rounding is needed with rounding
28.761 + * mode being set to RoundingMode.UNNECESSARY
28.762 + * @see java.text.FieldPosition
28.763 + */
28.764 + private StringBuffer format(BigInteger number, StringBuffer result,
28.765 + FieldPosition fieldPosition) {
28.766 + fieldPosition.setBeginIndex(0);
28.767 + fieldPosition.setEndIndex(0);
28.768 +
28.769 + return format(number, result, fieldPosition.getFieldDelegate(), false);
28.770 + }
28.771 +
28.772 + /**
28.773 + * Format a BigInteger to produce a string.
28.774 + * @param number The BigInteger to format
28.775 + * @param result where the text is to be appended
28.776 + * @param delegate notified of locations of sub fields
28.777 + * @return The formatted number string
28.778 + * @exception ArithmeticException if rounding is needed with rounding
28.779 + * mode being set to RoundingMode.UNNECESSARY
28.780 + * @see java.text.FieldPosition
28.781 + */
28.782 + private StringBuffer format(BigInteger number, StringBuffer result,
28.783 + FieldDelegate delegate, boolean formatLong) {
28.784 + if (multiplier != 1) {
28.785 + number = number.multiply(getBigIntegerMultiplier());
28.786 + }
28.787 + boolean isNegative = number.signum() == -1;
28.788 + if (isNegative) {
28.789 + number = number.negate();
28.790 + }
28.791 +
28.792 + synchronized(digitList) {
28.793 + int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
28.794 + if (formatLong) {
28.795 + maxIntDigits = super.getMaximumIntegerDigits();
28.796 + minIntDigits = super.getMinimumIntegerDigits();
28.797 + maxFraDigits = super.getMaximumFractionDigits();
28.798 + minFraDigits = super.getMinimumFractionDigits();
28.799 + maximumDigits = maxIntDigits + maxFraDigits;
28.800 + } else {
28.801 + maxIntDigits = getMaximumIntegerDigits();
28.802 + minIntDigits = getMinimumIntegerDigits();
28.803 + maxFraDigits = getMaximumFractionDigits();
28.804 + minFraDigits = getMinimumFractionDigits();
28.805 + maximumDigits = maxIntDigits + maxFraDigits;
28.806 + if (maximumDigits < 0) {
28.807 + maximumDigits = Integer.MAX_VALUE;
28.808 + }
28.809 + }
28.810 +
28.811 + digitList.set(isNegative, number,
28.812 + useExponentialNotation ? maximumDigits : 0);
28.813 +
28.814 + return subformat(result, delegate, isNegative, true,
28.815 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
28.816 + }
28.817 + }
28.818 +
28.819 + /**
28.820 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
28.821 + * You can use the returned <code>AttributedCharacterIterator</code>
28.822 + * to build the resulting String, as well as to determine information
28.823 + * about the resulting String.
28.824 + * <p>
28.825 + * Each attribute key of the AttributedCharacterIterator will be of type
28.826 + * <code>NumberFormat.Field</code>, with the attribute value being the
28.827 + * same as the attribute key.
28.828 + *
28.829 + * @exception NullPointerException if obj is null.
28.830 + * @exception IllegalArgumentException when the Format cannot format the
28.831 + * given object.
28.832 + * @exception ArithmeticException if rounding is needed with rounding
28.833 + * mode being set to RoundingMode.UNNECESSARY
28.834 + * @param obj The object to format
28.835 + * @return AttributedCharacterIterator describing the formatted value.
28.836 + * @since 1.4
28.837 + */
28.838 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
28.839 + CharacterIteratorFieldDelegate delegate =
28.840 + new CharacterIteratorFieldDelegate();
28.841 + StringBuffer sb = new StringBuffer();
28.842 +
28.843 + if (obj instanceof Double || obj instanceof Float) {
28.844 + format(((Number)obj).doubleValue(), sb, delegate);
28.845 + } else if (obj instanceof Long || obj instanceof Integer ||
28.846 + obj instanceof Short || obj instanceof Byte ||
28.847 + obj instanceof AtomicInteger || obj instanceof AtomicLong) {
28.848 + format(((Number)obj).longValue(), sb, delegate);
28.849 + } else if (obj instanceof BigDecimal) {
28.850 + format((BigDecimal)obj, sb, delegate);
28.851 + } else if (obj instanceof BigInteger) {
28.852 + format((BigInteger)obj, sb, delegate, false);
28.853 + } else if (obj == null) {
28.854 + throw new NullPointerException(
28.855 + "formatToCharacterIterator must be passed non-null object");
28.856 + } else {
28.857 + throw new IllegalArgumentException(
28.858 + "Cannot format given Object as a Number");
28.859 + }
28.860 + return delegate.getIterator(sb.toString());
28.861 + }
28.862 +
28.863 + /**
28.864 + * Complete the formatting of a finite number. On entry, the digitList must
28.865 + * be filled in with the correct digits.
28.866 + */
28.867 + private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
28.868 + boolean isNegative, boolean isInteger,
28.869 + int maxIntDigits, int minIntDigits,
28.870 + int maxFraDigits, int minFraDigits) {
28.871 + // NOTE: This isn't required anymore because DigitList takes care of this.
28.872 + //
28.873 + // // The negative of the exponent represents the number of leading
28.874 + // // zeros between the decimal and the first non-zero digit, for
28.875 + // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
28.876 + // // is more than the maximum fraction digits, then we have an underflow
28.877 + // // for the printed representation. We recognize this here and set
28.878 + // // the DigitList representation to zero in this situation.
28.879 + //
28.880 + // if (-digitList.decimalAt >= getMaximumFractionDigits())
28.881 + // {
28.882 + // digitList.count = 0;
28.883 + // }
28.884 +
28.885 + char zero = symbols.getZeroDigit();
28.886 + int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
28.887 + char grouping = symbols.getGroupingSeparator();
28.888 + char decimal = isCurrencyFormat ?
28.889 + symbols.getMonetaryDecimalSeparator() :
28.890 + symbols.getDecimalSeparator();
28.891 +
28.892 + /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
28.893 + * format as zero. This allows sensible computations and preserves
28.894 + * relations such as signum(1/x) = signum(x), where x is +Infinity or
28.895 + * -Infinity. Prior to this fix, we always formatted zero values as if
28.896 + * they were positive. Liu 7/6/98.
28.897 + */
28.898 + if (digitList.isZero()) {
28.899 + digitList.decimalAt = 0; // Normalize
28.900 + }
28.901 +
28.902 + if (isNegative) {
28.903 + append(result, negativePrefix, delegate,
28.904 + getNegativePrefixFieldPositions(), Field.SIGN);
28.905 + } else {
28.906 + append(result, positivePrefix, delegate,
28.907 + getPositivePrefixFieldPositions(), Field.SIGN);
28.908 + }
28.909 +
28.910 + if (useExponentialNotation) {
28.911 + int iFieldStart = result.length();
28.912 + int iFieldEnd = -1;
28.913 + int fFieldStart = -1;
28.914 +
28.915 + // Minimum integer digits are handled in exponential format by
28.916 + // adjusting the exponent. For example, 0.01234 with 3 minimum
28.917 + // integer digits is "123.4E-4".
28.918 +
28.919 + // Maximum integer digits are interpreted as indicating the
28.920 + // repeating range. This is useful for engineering notation, in
28.921 + // which the exponent is restricted to a multiple of 3. For
28.922 + // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
28.923 + // If maximum integer digits are > 1 and are larger than
28.924 + // minimum integer digits, then minimum integer digits are
28.925 + // ignored.
28.926 + int exponent = digitList.decimalAt;
28.927 + int repeat = maxIntDigits;
28.928 + int minimumIntegerDigits = minIntDigits;
28.929 + if (repeat > 1 && repeat > minIntDigits) {
28.930 + // A repeating range is defined; adjust to it as follows.
28.931 + // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
28.932 + // -3,-4,-5=>-6, etc. This takes into account that the
28.933 + // exponent we have here is off by one from what we expect;
28.934 + // it is for the format 0.MMMMMx10^n.
28.935 + if (exponent >= 1) {
28.936 + exponent = ((exponent - 1) / repeat) * repeat;
28.937 + } else {
28.938 + // integer division rounds towards 0
28.939 + exponent = ((exponent - repeat) / repeat) * repeat;
28.940 + }
28.941 + minimumIntegerDigits = 1;
28.942 + } else {
28.943 + // No repeating range is defined; use minimum integer digits.
28.944 + exponent -= minimumIntegerDigits;
28.945 + }
28.946 +
28.947 + // We now output a minimum number of digits, and more if there
28.948 + // are more digits, up to the maximum number of digits. We
28.949 + // place the decimal point after the "integer" digits, which
28.950 + // are the first (decimalAt - exponent) digits.
28.951 + int minimumDigits = minIntDigits + minFraDigits;
28.952 + if (minimumDigits < 0) { // overflow?
28.953 + minimumDigits = Integer.MAX_VALUE;
28.954 + }
28.955 +
28.956 + // The number of integer digits is handled specially if the number
28.957 + // is zero, since then there may be no digits.
28.958 + int integerDigits = digitList.isZero() ? minimumIntegerDigits :
28.959 + digitList.decimalAt - exponent;
28.960 + if (minimumDigits < integerDigits) {
28.961 + minimumDigits = integerDigits;
28.962 + }
28.963 + int totalDigits = digitList.count;
28.964 + if (minimumDigits > totalDigits) {
28.965 + totalDigits = minimumDigits;
28.966 + }
28.967 + boolean addedDecimalSeparator = false;
28.968 +
28.969 + for (int i=0; i<totalDigits; ++i) {
28.970 + if (i == integerDigits) {
28.971 + // Record field information for caller.
28.972 + iFieldEnd = result.length();
28.973 +
28.974 + result.append(decimal);
28.975 + addedDecimalSeparator = true;
28.976 +
28.977 + // Record field information for caller.
28.978 + fFieldStart = result.length();
28.979 + }
28.980 + result.append((i < digitList.count) ?
28.981 + (char)(digitList.digits[i] + zeroDelta) :
28.982 + zero);
28.983 + }
28.984 +
28.985 + if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
28.986 + // Record field information for caller.
28.987 + iFieldEnd = result.length();
28.988 +
28.989 + result.append(decimal);
28.990 + addedDecimalSeparator = true;
28.991 +
28.992 + // Record field information for caller.
28.993 + fFieldStart = result.length();
28.994 + }
28.995 +
28.996 + // Record field information
28.997 + if (iFieldEnd == -1) {
28.998 + iFieldEnd = result.length();
28.999 + }
28.1000 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
28.1001 + iFieldStart, iFieldEnd, result);
28.1002 + if (addedDecimalSeparator) {
28.1003 + delegate.formatted(Field.DECIMAL_SEPARATOR,
28.1004 + Field.DECIMAL_SEPARATOR,
28.1005 + iFieldEnd, fFieldStart, result);
28.1006 + }
28.1007 + if (fFieldStart == -1) {
28.1008 + fFieldStart = result.length();
28.1009 + }
28.1010 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
28.1011 + fFieldStart, result.length(), result);
28.1012 +
28.1013 + // The exponent is output using the pattern-specified minimum
28.1014 + // exponent digits. There is no maximum limit to the exponent
28.1015 + // digits, since truncating the exponent would result in an
28.1016 + // unacceptable inaccuracy.
28.1017 + int fieldStart = result.length();
28.1018 +
28.1019 + result.append(symbols.getExponentSeparator());
28.1020 +
28.1021 + delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
28.1022 + fieldStart, result.length(), result);
28.1023 +
28.1024 + // For zero values, we force the exponent to zero. We
28.1025 + // must do this here, and not earlier, because the value
28.1026 + // is used to determine integer digit count above.
28.1027 + if (digitList.isZero()) {
28.1028 + exponent = 0;
28.1029 + }
28.1030 +
28.1031 + boolean negativeExponent = exponent < 0;
28.1032 + if (negativeExponent) {
28.1033 + exponent = -exponent;
28.1034 + fieldStart = result.length();
28.1035 + result.append(symbols.getMinusSign());
28.1036 + delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
28.1037 + fieldStart, result.length(), result);
28.1038 + }
28.1039 + digitList.set(negativeExponent, exponent);
28.1040 +
28.1041 + int eFieldStart = result.length();
28.1042 +
28.1043 + for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
28.1044 + result.append(zero);
28.1045 + }
28.1046 + for (int i=0; i<digitList.decimalAt; ++i) {
28.1047 + result.append((i < digitList.count) ?
28.1048 + (char)(digitList.digits[i] + zeroDelta) : zero);
28.1049 + }
28.1050 + delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
28.1051 + result.length(), result);
28.1052 + } else {
28.1053 + int iFieldStart = result.length();
28.1054 +
28.1055 + // Output the integer portion. Here 'count' is the total
28.1056 + // number of integer digits we will display, including both
28.1057 + // leading zeros required to satisfy getMinimumIntegerDigits,
28.1058 + // and actual digits present in the number.
28.1059 + int count = minIntDigits;
28.1060 + int digitIndex = 0; // Index into digitList.fDigits[]
28.1061 + if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
28.1062 + count = digitList.decimalAt;
28.1063 + }
28.1064 +
28.1065 + // Handle the case where getMaximumIntegerDigits() is smaller
28.1066 + // than the real number of integer digits. If this is so, we
28.1067 + // output the least significant max integer digits. For example,
28.1068 + // the value 1997 printed with 2 max integer digits is just "97".
28.1069 + if (count > maxIntDigits) {
28.1070 + count = maxIntDigits;
28.1071 + digitIndex = digitList.decimalAt - count;
28.1072 + }
28.1073 +
28.1074 + int sizeBeforeIntegerPart = result.length();
28.1075 + for (int i=count-1; i>=0; --i) {
28.1076 + if (i < digitList.decimalAt && digitIndex < digitList.count) {
28.1077 + // Output a real digit
28.1078 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
28.1079 + } else {
28.1080 + // Output a leading zero
28.1081 + result.append(zero);
28.1082 + }
28.1083 +
28.1084 + // Output grouping separator if necessary. Don't output a
28.1085 + // grouping separator if i==0 though; that's at the end of
28.1086 + // the integer part.
28.1087 + if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
28.1088 + (i % groupingSize == 0)) {
28.1089 + int gStart = result.length();
28.1090 + result.append(grouping);
28.1091 + delegate.formatted(Field.GROUPING_SEPARATOR,
28.1092 + Field.GROUPING_SEPARATOR, gStart,
28.1093 + result.length(), result);
28.1094 + }
28.1095 + }
28.1096 +
28.1097 + // Determine whether or not there are any printable fractional
28.1098 + // digits. If we've used up the digits we know there aren't.
28.1099 + boolean fractionPresent = (minFraDigits > 0) ||
28.1100 + (!isInteger && digitIndex < digitList.count);
28.1101 +
28.1102 + // If there is no fraction present, and we haven't printed any
28.1103 + // integer digits, then print a zero. Otherwise we won't print
28.1104 + // _any_ digits, and we won't be able to parse this string.
28.1105 + if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
28.1106 + result.append(zero);
28.1107 + }
28.1108 +
28.1109 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
28.1110 + iFieldStart, result.length(), result);
28.1111 +
28.1112 + // Output the decimal separator if we always do so.
28.1113 + int sStart = result.length();
28.1114 + if (decimalSeparatorAlwaysShown || fractionPresent) {
28.1115 + result.append(decimal);
28.1116 + }
28.1117 +
28.1118 + if (sStart != result.length()) {
28.1119 + delegate.formatted(Field.DECIMAL_SEPARATOR,
28.1120 + Field.DECIMAL_SEPARATOR,
28.1121 + sStart, result.length(), result);
28.1122 + }
28.1123 + int fFieldStart = result.length();
28.1124 +
28.1125 + for (int i=0; i < maxFraDigits; ++i) {
28.1126 + // Here is where we escape from the loop. We escape if we've
28.1127 + // output the maximum fraction digits (specified in the for
28.1128 + // expression above).
28.1129 + // We also stop when we've output the minimum digits and either:
28.1130 + // we have an integer, so there is no fractional stuff to
28.1131 + // display, or we're out of significant digits.
28.1132 + if (i >= minFraDigits &&
28.1133 + (isInteger || digitIndex >= digitList.count)) {
28.1134 + break;
28.1135 + }
28.1136 +
28.1137 + // Output leading fractional zeros. These are zeros that come
28.1138 + // after the decimal but before any significant digits. These
28.1139 + // are only output if abs(number being formatted) < 1.0.
28.1140 + if (-1-i > (digitList.decimalAt-1)) {
28.1141 + result.append(zero);
28.1142 + continue;
28.1143 + }
28.1144 +
28.1145 + // Output a digit, if we have any precision left, or a
28.1146 + // zero if we don't. We don't want to output noise digits.
28.1147 + if (!isInteger && digitIndex < digitList.count) {
28.1148 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
28.1149 + } else {
28.1150 + result.append(zero);
28.1151 + }
28.1152 + }
28.1153 +
28.1154 + // Record field information for caller.
28.1155 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
28.1156 + fFieldStart, result.length(), result);
28.1157 + }
28.1158 +
28.1159 + if (isNegative) {
28.1160 + append(result, negativeSuffix, delegate,
28.1161 + getNegativeSuffixFieldPositions(), Field.SIGN);
28.1162 + }
28.1163 + else {
28.1164 + append(result, positiveSuffix, delegate,
28.1165 + getPositiveSuffixFieldPositions(), Field.SIGN);
28.1166 + }
28.1167 +
28.1168 + return result;
28.1169 + }
28.1170 +
28.1171 + /**
28.1172 + * Appends the String <code>string</code> to <code>result</code>.
28.1173 + * <code>delegate</code> is notified of all the
28.1174 + * <code>FieldPosition</code>s in <code>positions</code>.
28.1175 + * <p>
28.1176 + * If one of the <code>FieldPosition</code>s in <code>positions</code>
28.1177 + * identifies a <code>SIGN</code> attribute, it is mapped to
28.1178 + * <code>signAttribute</code>. This is used
28.1179 + * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
28.1180 + * attribute as necessary.
28.1181 + * <p>
28.1182 + * This is used by <code>subformat</code> to add the prefix/suffix.
28.1183 + */
28.1184 + private void append(StringBuffer result, String string,
28.1185 + FieldDelegate delegate,
28.1186 + FieldPosition[] positions,
28.1187 + Format.Field signAttribute) {
28.1188 + int start = result.length();
28.1189 +
28.1190 + if (string.length() > 0) {
28.1191 + result.append(string);
28.1192 + for (int counter = 0, max = positions.length; counter < max;
28.1193 + counter++) {
28.1194 + FieldPosition fp = positions[counter];
28.1195 + Format.Field attribute = fp.getFieldAttribute();
28.1196 +
28.1197 + if (attribute == Field.SIGN) {
28.1198 + attribute = signAttribute;
28.1199 + }
28.1200 + delegate.formatted(attribute, attribute,
28.1201 + start + fp.getBeginIndex(),
28.1202 + start + fp.getEndIndex(), result);
28.1203 + }
28.1204 + }
28.1205 + }
28.1206 +
28.1207 + /**
28.1208 + * Parses text from a string to produce a <code>Number</code>.
28.1209 + * <p>
28.1210 + * The method attempts to parse text starting at the index given by
28.1211 + * <code>pos</code>.
28.1212 + * If parsing succeeds, then the index of <code>pos</code> is updated
28.1213 + * to the index after the last character used (parsing does not necessarily
28.1214 + * use all characters up to the end of the string), and the parsed
28.1215 + * number is returned. The updated <code>pos</code> can be used to
28.1216 + * indicate the starting point for the next call to this method.
28.1217 + * If an error occurs, then the index of <code>pos</code> is not
28.1218 + * changed, the error index of <code>pos</code> is set to the index of
28.1219 + * the character where the error occurred, and null is returned.
28.1220 + * <p>
28.1221 + * The subclass returned depends on the value of {@link #isParseBigDecimal}
28.1222 + * as well as on the string being parsed.
28.1223 + * <ul>
28.1224 + * <li>If <code>isParseBigDecimal()</code> is false (the default),
28.1225 + * most integer values are returned as <code>Long</code>
28.1226 + * objects, no matter how they are written: <code>"17"</code> and
28.1227 + * <code>"17.000"</code> both parse to <code>Long(17)</code>.
28.1228 + * Values that cannot fit into a <code>Long</code> are returned as
28.1229 + * <code>Double</code>s. This includes values with a fractional part,
28.1230 + * infinite values, <code>NaN</code>, and the value -0.0.
28.1231 + * <code>DecimalFormat</code> does <em>not</em> decide whether to
28.1232 + * return a <code>Double</code> or a <code>Long</code> based on the
28.1233 + * presence of a decimal separator in the source string. Doing so
28.1234 + * would prevent integers that overflow the mantissa of a double,
28.1235 + * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
28.1236 + * parsed accurately.
28.1237 + * <p>
28.1238 + * Callers may use the <code>Number</code> methods
28.1239 + * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
28.1240 + * the type they want.
28.1241 + * <li>If <code>isParseBigDecimal()</code> is true, values are returned
28.1242 + * as <code>BigDecimal</code> objects. The values are the ones
28.1243 + * constructed by {@link java.math.BigDecimal#BigDecimal(String)}
28.1244 + * for corresponding strings in locale-independent format. The
28.1245 + * special cases negative and positive infinity and NaN are returned
28.1246 + * as <code>Double</code> instances holding the values of the
28.1247 + * corresponding <code>Double</code> constants.
28.1248 + * </ul>
28.1249 + * <p>
28.1250 + * <code>DecimalFormat</code> parses all Unicode characters that represent
28.1251 + * decimal digits, as defined by <code>Character.digit()</code>. In
28.1252 + * addition, <code>DecimalFormat</code> also recognizes as digits the ten
28.1253 + * consecutive characters starting with the localized zero digit defined in
28.1254 + * the <code>DecimalFormatSymbols</code> object.
28.1255 + *
28.1256 + * @param text the string to be parsed
28.1257 + * @param pos A <code>ParsePosition</code> object with index and error
28.1258 + * index information as described above.
28.1259 + * @return the parsed value, or <code>null</code> if the parse fails
28.1260 + * @exception NullPointerException if <code>text</code> or
28.1261 + * <code>pos</code> is null.
28.1262 + */
28.1263 + public Number parse(String text, ParsePosition pos) {
28.1264 + // special case NaN
28.1265 + if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
28.1266 + pos.index = pos.index + symbols.getNaN().length();
28.1267 + return new Double(Double.NaN);
28.1268 + }
28.1269 +
28.1270 + boolean[] status = new boolean[STATUS_LENGTH];
28.1271 + if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
28.1272 + return null;
28.1273 + }
28.1274 +
28.1275 + // special case INFINITY
28.1276 + if (status[STATUS_INFINITE]) {
28.1277 + if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
28.1278 + return new Double(Double.POSITIVE_INFINITY);
28.1279 + } else {
28.1280 + return new Double(Double.NEGATIVE_INFINITY);
28.1281 + }
28.1282 + }
28.1283 +
28.1284 + if (multiplier == 0) {
28.1285 + if (digitList.isZero()) {
28.1286 + return new Double(Double.NaN);
28.1287 + } else if (status[STATUS_POSITIVE]) {
28.1288 + return new Double(Double.POSITIVE_INFINITY);
28.1289 + } else {
28.1290 + return new Double(Double.NEGATIVE_INFINITY);
28.1291 + }
28.1292 + }
28.1293 +
28.1294 + if (isParseBigDecimal()) {
28.1295 + BigDecimal bigDecimalResult = digitList.getBigDecimal();
28.1296 +
28.1297 + if (multiplier != 1) {
28.1298 + try {
28.1299 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
28.1300 + }
28.1301 + catch (ArithmeticException e) { // non-terminating decimal expansion
28.1302 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
28.1303 + }
28.1304 + }
28.1305 +
28.1306 + if (!status[STATUS_POSITIVE]) {
28.1307 + bigDecimalResult = bigDecimalResult.negate();
28.1308 + }
28.1309 + return bigDecimalResult;
28.1310 + } else {
28.1311 + boolean gotDouble = true;
28.1312 + boolean gotLongMinimum = false;
28.1313 + double doubleResult = 0.0;
28.1314 + long longResult = 0;
28.1315 +
28.1316 + // Finally, have DigitList parse the digits into a value.
28.1317 + if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
28.1318 + gotDouble = false;
28.1319 + longResult = digitList.getLong();
28.1320 + if (longResult < 0) { // got Long.MIN_VALUE
28.1321 + gotLongMinimum = true;
28.1322 + }
28.1323 + } else {
28.1324 + doubleResult = digitList.getDouble();
28.1325 + }
28.1326 +
28.1327 + // Divide by multiplier. We have to be careful here not to do
28.1328 + // unneeded conversions between double and long.
28.1329 + if (multiplier != 1) {
28.1330 + if (gotDouble) {
28.1331 + doubleResult /= multiplier;
28.1332 + } else {
28.1333 + // Avoid converting to double if we can
28.1334 + if (longResult % multiplier == 0) {
28.1335 + longResult /= multiplier;
28.1336 + } else {
28.1337 + doubleResult = ((double)longResult) / multiplier;
28.1338 + gotDouble = true;
28.1339 + }
28.1340 + }
28.1341 + }
28.1342 +
28.1343 + if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
28.1344 + doubleResult = -doubleResult;
28.1345 + longResult = -longResult;
28.1346 + }
28.1347 +
28.1348 + // At this point, if we divided the result by the multiplier, the
28.1349 + // result may fit into a long. We check for this case and return
28.1350 + // a long if possible.
28.1351 + // We must do this AFTER applying the negative (if appropriate)
28.1352 + // in order to handle the case of LONG_MIN; otherwise, if we do
28.1353 + // this with a positive value -LONG_MIN, the double is > 0, but
28.1354 + // the long is < 0. We also must retain a double in the case of
28.1355 + // -0.0, which will compare as == to a long 0 cast to a double
28.1356 + // (bug 4162852).
28.1357 + if (multiplier != 1 && gotDouble) {
28.1358 + longResult = (long)doubleResult;
28.1359 + gotDouble = ((doubleResult != (double)longResult) ||
28.1360 + (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
28.1361 + !isParseIntegerOnly();
28.1362 + }
28.1363 +
28.1364 + return gotDouble ?
28.1365 + (Number)new Double(doubleResult) : (Number)new Long(longResult);
28.1366 + }
28.1367 + }
28.1368 +
28.1369 + /**
28.1370 + * Return a BigInteger multiplier.
28.1371 + */
28.1372 + private BigInteger getBigIntegerMultiplier() {
28.1373 + if (bigIntegerMultiplier == null) {
28.1374 + bigIntegerMultiplier = BigInteger.valueOf(multiplier);
28.1375 + }
28.1376 + return bigIntegerMultiplier;
28.1377 + }
28.1378 + private transient BigInteger bigIntegerMultiplier;
28.1379 +
28.1380 + /**
28.1381 + * Return a BigDecimal multiplier.
28.1382 + */
28.1383 + private BigDecimal getBigDecimalMultiplier() {
28.1384 + if (bigDecimalMultiplier == null) {
28.1385 + bigDecimalMultiplier = new BigDecimal(multiplier);
28.1386 + }
28.1387 + return bigDecimalMultiplier;
28.1388 + }
28.1389 + private transient BigDecimal bigDecimalMultiplier;
28.1390 +
28.1391 + private static final int STATUS_INFINITE = 0;
28.1392 + private static final int STATUS_POSITIVE = 1;
28.1393 + private static final int STATUS_LENGTH = 2;
28.1394 +
28.1395 + /**
28.1396 + * Parse the given text into a number. The text is parsed beginning at
28.1397 + * parsePosition, until an unparseable character is seen.
28.1398 + * @param text The string to parse.
28.1399 + * @param parsePosition The position at which to being parsing. Upon
28.1400 + * return, the first unparseable character.
28.1401 + * @param digits The DigitList to set to the parsed value.
28.1402 + * @param isExponent If true, parse an exponent. This means no
28.1403 + * infinite values and integer only.
28.1404 + * @param status Upon return contains boolean status flags indicating
28.1405 + * whether the value was infinite and whether it was positive.
28.1406 + */
28.1407 + private final boolean subparse(String text, ParsePosition parsePosition,
28.1408 + String positivePrefix, String negativePrefix,
28.1409 + DigitList digits, boolean isExponent,
28.1410 + boolean status[]) {
28.1411 + int position = parsePosition.index;
28.1412 + int oldStart = parsePosition.index;
28.1413 + int backup;
28.1414 + boolean gotPositive, gotNegative;
28.1415 +
28.1416 + // check for positivePrefix; take longest
28.1417 + gotPositive = text.regionMatches(position, positivePrefix, 0,
28.1418 + positivePrefix.length());
28.1419 + gotNegative = text.regionMatches(position, negativePrefix, 0,
28.1420 + negativePrefix.length());
28.1421 +
28.1422 + if (gotPositive && gotNegative) {
28.1423 + if (positivePrefix.length() > negativePrefix.length()) {
28.1424 + gotNegative = false;
28.1425 + } else if (positivePrefix.length() < negativePrefix.length()) {
28.1426 + gotPositive = false;
28.1427 + }
28.1428 + }
28.1429 +
28.1430 + if (gotPositive) {
28.1431 + position += positivePrefix.length();
28.1432 + } else if (gotNegative) {
28.1433 + position += negativePrefix.length();
28.1434 + } else {
28.1435 + parsePosition.errorIndex = position;
28.1436 + return false;
28.1437 + }
28.1438 +
28.1439 + // process digits or Inf, find decimal position
28.1440 + status[STATUS_INFINITE] = false;
28.1441 + if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
28.1442 + symbols.getInfinity().length())) {
28.1443 + position += symbols.getInfinity().length();
28.1444 + status[STATUS_INFINITE] = true;
28.1445 + } else {
28.1446 + // We now have a string of digits, possibly with grouping symbols,
28.1447 + // and decimal points. We want to process these into a DigitList.
28.1448 + // We don't want to put a bunch of leading zeros into the DigitList
28.1449 + // though, so we keep track of the location of the decimal point,
28.1450 + // put only significant digits into the DigitList, and adjust the
28.1451 + // exponent as needed.
28.1452 +
28.1453 + digits.decimalAt = digits.count = 0;
28.1454 + char zero = symbols.getZeroDigit();
28.1455 + char decimal = isCurrencyFormat ?
28.1456 + symbols.getMonetaryDecimalSeparator() :
28.1457 + symbols.getDecimalSeparator();
28.1458 + char grouping = symbols.getGroupingSeparator();
28.1459 + String exponentString = symbols.getExponentSeparator();
28.1460 + boolean sawDecimal = false;
28.1461 + boolean sawExponent = false;
28.1462 + boolean sawDigit = false;
28.1463 + int exponent = 0; // Set to the exponent value, if any
28.1464 +
28.1465 + // We have to track digitCount ourselves, because digits.count will
28.1466 + // pin when the maximum allowable digits is reached.
28.1467 + int digitCount = 0;
28.1468 +
28.1469 + backup = -1;
28.1470 + for (; position < text.length(); ++position) {
28.1471 + char ch = text.charAt(position);
28.1472 +
28.1473 + /* We recognize all digit ranges, not only the Latin digit range
28.1474 + * '0'..'9'. We do so by using the Character.digit() method,
28.1475 + * which converts a valid Unicode digit to the range 0..9.
28.1476 + *
28.1477 + * The character 'ch' may be a digit. If so, place its value
28.1478 + * from 0 to 9 in 'digit'. First try using the locale digit,
28.1479 + * which may or MAY NOT be a standard Unicode digit range. If
28.1480 + * this fails, try using the standard Unicode digit ranges by
28.1481 + * calling Character.digit(). If this also fails, digit will
28.1482 + * have a value outside the range 0..9.
28.1483 + */
28.1484 + int digit = ch - zero;
28.1485 + if (digit < 0 || digit > 9) {
28.1486 + digit = Character.digit(ch, 10);
28.1487 + }
28.1488 +
28.1489 + if (digit == 0) {
28.1490 + // Cancel out backup setting (see grouping handler below)
28.1491 + backup = -1; // Do this BEFORE continue statement below!!!
28.1492 + sawDigit = true;
28.1493 +
28.1494 + // Handle leading zeros
28.1495 + if (digits.count == 0) {
28.1496 + // Ignore leading zeros in integer part of number.
28.1497 + if (!sawDecimal) {
28.1498 + continue;
28.1499 + }
28.1500 +
28.1501 + // If we have seen the decimal, but no significant
28.1502 + // digits yet, then we account for leading zeros by
28.1503 + // decrementing the digits.decimalAt into negative
28.1504 + // values.
28.1505 + --digits.decimalAt;
28.1506 + } else {
28.1507 + ++digitCount;
28.1508 + digits.append((char)(digit + '0'));
28.1509 + }
28.1510 + } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
28.1511 + sawDigit = true;
28.1512 + ++digitCount;
28.1513 + digits.append((char)(digit + '0'));
28.1514 +
28.1515 + // Cancel out backup setting (see grouping handler below)
28.1516 + backup = -1;
28.1517 + } else if (!isExponent && ch == decimal) {
28.1518 + // If we're only parsing integers, or if we ALREADY saw the
28.1519 + // decimal, then don't parse this one.
28.1520 + if (isParseIntegerOnly() || sawDecimal) {
28.1521 + break;
28.1522 + }
28.1523 + digits.decimalAt = digitCount; // Not digits.count!
28.1524 + sawDecimal = true;
28.1525 + } else if (!isExponent && ch == grouping && isGroupingUsed()) {
28.1526 + if (sawDecimal) {
28.1527 + break;
28.1528 + }
28.1529 + // Ignore grouping characters, if we are using them, but
28.1530 + // require that they be followed by a digit. Otherwise
28.1531 + // we backup and reprocess them.
28.1532 + backup = position;
28.1533 + } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
28.1534 + && !sawExponent) {
28.1535 + // Process the exponent by recursively calling this method.
28.1536 + ParsePosition pos = new ParsePosition(position + exponentString.length());
28.1537 + boolean[] stat = new boolean[STATUS_LENGTH];
28.1538 + DigitList exponentDigits = new DigitList();
28.1539 +
28.1540 + if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
28.1541 + exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
28.1542 + position = pos.index; // Advance past the exponent
28.1543 + exponent = (int)exponentDigits.getLong();
28.1544 + if (!stat[STATUS_POSITIVE]) {
28.1545 + exponent = -exponent;
28.1546 + }
28.1547 + sawExponent = true;
28.1548 + }
28.1549 + break; // Whether we fail or succeed, we exit this loop
28.1550 + }
28.1551 + else {
28.1552 + break;
28.1553 + }
28.1554 + }
28.1555 +
28.1556 + if (backup != -1) {
28.1557 + position = backup;
28.1558 + }
28.1559 +
28.1560 + // If there was no decimal point we have an integer
28.1561 + if (!sawDecimal) {
28.1562 + digits.decimalAt = digitCount; // Not digits.count!
28.1563 + }
28.1564 +
28.1565 + // Adjust for exponent, if any
28.1566 + digits.decimalAt += exponent;
28.1567 +
28.1568 + // If none of the text string was recognized. For example, parse
28.1569 + // "x" with pattern "#0.00" (return index and error index both 0)
28.1570 + // parse "$" with pattern "$#0.00". (return index 0 and error
28.1571 + // index 1).
28.1572 + if (!sawDigit && digitCount == 0) {
28.1573 + parsePosition.index = oldStart;
28.1574 + parsePosition.errorIndex = oldStart;
28.1575 + return false;
28.1576 + }
28.1577 + }
28.1578 +
28.1579 + // check for suffix
28.1580 + if (!isExponent) {
28.1581 + if (gotPositive) {
28.1582 + gotPositive = text.regionMatches(position,positiveSuffix,0,
28.1583 + positiveSuffix.length());
28.1584 + }
28.1585 + if (gotNegative) {
28.1586 + gotNegative = text.regionMatches(position,negativeSuffix,0,
28.1587 + negativeSuffix.length());
28.1588 + }
28.1589 +
28.1590 + // if both match, take longest
28.1591 + if (gotPositive && gotNegative) {
28.1592 + if (positiveSuffix.length() > negativeSuffix.length()) {
28.1593 + gotNegative = false;
28.1594 + } else if (positiveSuffix.length() < negativeSuffix.length()) {
28.1595 + gotPositive = false;
28.1596 + }
28.1597 + }
28.1598 +
28.1599 + // fail if neither or both
28.1600 + if (gotPositive == gotNegative) {
28.1601 + parsePosition.errorIndex = position;
28.1602 + return false;
28.1603 + }
28.1604 +
28.1605 + parsePosition.index = position +
28.1606 + (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
28.1607 + } else {
28.1608 + parsePosition.index = position;
28.1609 + }
28.1610 +
28.1611 + status[STATUS_POSITIVE] = gotPositive;
28.1612 + if (parsePosition.index == oldStart) {
28.1613 + parsePosition.errorIndex = position;
28.1614 + return false;
28.1615 + }
28.1616 + return true;
28.1617 + }
28.1618 +
28.1619 + /**
28.1620 + * Returns a copy of the decimal format symbols, which is generally not
28.1621 + * changed by the programmer or user.
28.1622 + * @return a copy of the desired DecimalFormatSymbols
28.1623 + * @see java.text.DecimalFormatSymbols
28.1624 + */
28.1625 + public DecimalFormatSymbols getDecimalFormatSymbols() {
28.1626 + try {
28.1627 + // don't allow multiple references
28.1628 + return (DecimalFormatSymbols) symbols.clone();
28.1629 + } catch (Exception foo) {
28.1630 + return null; // should never happen
28.1631 + }
28.1632 + }
28.1633 +
28.1634 +
28.1635 + /**
28.1636 + * Sets the decimal format symbols, which is generally not changed
28.1637 + * by the programmer or user.
28.1638 + * @param newSymbols desired DecimalFormatSymbols
28.1639 + * @see java.text.DecimalFormatSymbols
28.1640 + */
28.1641 + public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
28.1642 + try {
28.1643 + // don't allow multiple references
28.1644 + symbols = (DecimalFormatSymbols) newSymbols.clone();
28.1645 + expandAffixes();
28.1646 + } catch (Exception foo) {
28.1647 + // should never happen
28.1648 + }
28.1649 + }
28.1650 +
28.1651 + /**
28.1652 + * Get the positive prefix.
28.1653 + * <P>Examples: +123, $123, sFr123
28.1654 + */
28.1655 + public String getPositivePrefix () {
28.1656 + return positivePrefix;
28.1657 + }
28.1658 +
28.1659 + /**
28.1660 + * Set the positive prefix.
28.1661 + * <P>Examples: +123, $123, sFr123
28.1662 + */
28.1663 + public void setPositivePrefix (String newValue) {
28.1664 + positivePrefix = newValue;
28.1665 + posPrefixPattern = null;
28.1666 + positivePrefixFieldPositions = null;
28.1667 + }
28.1668 +
28.1669 + /**
28.1670 + * Returns the FieldPositions of the fields in the prefix used for
28.1671 + * positive numbers. This is not used if the user has explicitly set
28.1672 + * a positive prefix via <code>setPositivePrefix</code>. This is
28.1673 + * lazily created.
28.1674 + *
28.1675 + * @return FieldPositions in positive prefix
28.1676 + */
28.1677 + private FieldPosition[] getPositivePrefixFieldPositions() {
28.1678 + if (positivePrefixFieldPositions == null) {
28.1679 + if (posPrefixPattern != null) {
28.1680 + positivePrefixFieldPositions = expandAffix(posPrefixPattern);
28.1681 + }
28.1682 + else {
28.1683 + positivePrefixFieldPositions = EmptyFieldPositionArray;
28.1684 + }
28.1685 + }
28.1686 + return positivePrefixFieldPositions;
28.1687 + }
28.1688 +
28.1689 + /**
28.1690 + * Get the negative prefix.
28.1691 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
28.1692 + */
28.1693 + public String getNegativePrefix () {
28.1694 + return negativePrefix;
28.1695 + }
28.1696 +
28.1697 + /**
28.1698 + * Set the negative prefix.
28.1699 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
28.1700 + */
28.1701 + public void setNegativePrefix (String newValue) {
28.1702 + negativePrefix = newValue;
28.1703 + negPrefixPattern = null;
28.1704 + }
28.1705 +
28.1706 + /**
28.1707 + * Returns the FieldPositions of the fields in the prefix used for
28.1708 + * negative numbers. This is not used if the user has explicitly set
28.1709 + * a negative prefix via <code>setNegativePrefix</code>. This is
28.1710 + * lazily created.
28.1711 + *
28.1712 + * @return FieldPositions in positive prefix
28.1713 + */
28.1714 + private FieldPosition[] getNegativePrefixFieldPositions() {
28.1715 + if (negativePrefixFieldPositions == null) {
28.1716 + if (negPrefixPattern != null) {
28.1717 + negativePrefixFieldPositions = expandAffix(negPrefixPattern);
28.1718 + }
28.1719 + else {
28.1720 + negativePrefixFieldPositions = EmptyFieldPositionArray;
28.1721 + }
28.1722 + }
28.1723 + return negativePrefixFieldPositions;
28.1724 + }
28.1725 +
28.1726 + /**
28.1727 + * Get the positive suffix.
28.1728 + * <P>Example: 123%
28.1729 + */
28.1730 + public String getPositiveSuffix () {
28.1731 + return positiveSuffix;
28.1732 + }
28.1733 +
28.1734 + /**
28.1735 + * Set the positive suffix.
28.1736 + * <P>Example: 123%
28.1737 + */
28.1738 + public void setPositiveSuffix (String newValue) {
28.1739 + positiveSuffix = newValue;
28.1740 + posSuffixPattern = null;
28.1741 + }
28.1742 +
28.1743 + /**
28.1744 + * Returns the FieldPositions of the fields in the suffix used for
28.1745 + * positive numbers. This is not used if the user has explicitly set
28.1746 + * a positive suffix via <code>setPositiveSuffix</code>. This is
28.1747 + * lazily created.
28.1748 + *
28.1749 + * @return FieldPositions in positive prefix
28.1750 + */
28.1751 + private FieldPosition[] getPositiveSuffixFieldPositions() {
28.1752 + if (positiveSuffixFieldPositions == null) {
28.1753 + if (posSuffixPattern != null) {
28.1754 + positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
28.1755 + }
28.1756 + else {
28.1757 + positiveSuffixFieldPositions = EmptyFieldPositionArray;
28.1758 + }
28.1759 + }
28.1760 + return positiveSuffixFieldPositions;
28.1761 + }
28.1762 +
28.1763 + /**
28.1764 + * Get the negative suffix.
28.1765 + * <P>Examples: -123%, ($123) (with positive suffixes)
28.1766 + */
28.1767 + public String getNegativeSuffix () {
28.1768 + return negativeSuffix;
28.1769 + }
28.1770 +
28.1771 + /**
28.1772 + * Set the negative suffix.
28.1773 + * <P>Examples: 123%
28.1774 + */
28.1775 + public void setNegativeSuffix (String newValue) {
28.1776 + negativeSuffix = newValue;
28.1777 + negSuffixPattern = null;
28.1778 + }
28.1779 +
28.1780 + /**
28.1781 + * Returns the FieldPositions of the fields in the suffix used for
28.1782 + * negative numbers. This is not used if the user has explicitly set
28.1783 + * a negative suffix via <code>setNegativeSuffix</code>. This is
28.1784 + * lazily created.
28.1785 + *
28.1786 + * @return FieldPositions in positive prefix
28.1787 + */
28.1788 + private FieldPosition[] getNegativeSuffixFieldPositions() {
28.1789 + if (negativeSuffixFieldPositions == null) {
28.1790 + if (negSuffixPattern != null) {
28.1791 + negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
28.1792 + }
28.1793 + else {
28.1794 + negativeSuffixFieldPositions = EmptyFieldPositionArray;
28.1795 + }
28.1796 + }
28.1797 + return negativeSuffixFieldPositions;
28.1798 + }
28.1799 +
28.1800 + /**
28.1801 + * Gets the multiplier for use in percent, per mille, and similar
28.1802 + * formats.
28.1803 + *
28.1804 + * @see #setMultiplier(int)
28.1805 + */
28.1806 + public int getMultiplier () {
28.1807 + return multiplier;
28.1808 + }
28.1809 +
28.1810 + /**
28.1811 + * Sets the multiplier for use in percent, per mille, and similar
28.1812 + * formats.
28.1813 + * For a percent format, set the multiplier to 100 and the suffixes to
28.1814 + * have '%' (for Arabic, use the Arabic percent sign).
28.1815 + * For a per mille format, set the multiplier to 1000 and the suffixes to
28.1816 + * have '\u2030'.
28.1817 + *
28.1818 + * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
28.1819 + * "123" is parsed into 1.23.
28.1820 + *
28.1821 + * @see #getMultiplier
28.1822 + */
28.1823 + public void setMultiplier (int newValue) {
28.1824 + multiplier = newValue;
28.1825 + bigDecimalMultiplier = null;
28.1826 + bigIntegerMultiplier = null;
28.1827 + }
28.1828 +
28.1829 + /**
28.1830 + * Return the grouping size. Grouping size is the number of digits between
28.1831 + * grouping separators in the integer portion of a number. For example,
28.1832 + * in the number "123,456.78", the grouping size is 3.
28.1833 + * @see #setGroupingSize
28.1834 + * @see java.text.NumberFormat#isGroupingUsed
28.1835 + * @see java.text.DecimalFormatSymbols#getGroupingSeparator
28.1836 + */
28.1837 + public int getGroupingSize () {
28.1838 + return groupingSize;
28.1839 + }
28.1840 +
28.1841 + /**
28.1842 + * Set the grouping size. Grouping size is the number of digits between
28.1843 + * grouping separators in the integer portion of a number. For example,
28.1844 + * in the number "123,456.78", the grouping size is 3.
28.1845 + * <br>
28.1846 + * The value passed in is converted to a byte, which may lose information.
28.1847 + * @see #getGroupingSize
28.1848 + * @see java.text.NumberFormat#setGroupingUsed
28.1849 + * @see java.text.DecimalFormatSymbols#setGroupingSeparator
28.1850 + */
28.1851 + public void setGroupingSize (int newValue) {
28.1852 + groupingSize = (byte)newValue;
28.1853 + }
28.1854 +
28.1855 + /**
28.1856 + * Allows you to get the behavior of the decimal separator with integers.
28.1857 + * (The decimal separator will always appear with decimals.)
28.1858 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
28.1859 + */
28.1860 + public boolean isDecimalSeparatorAlwaysShown() {
28.1861 + return decimalSeparatorAlwaysShown;
28.1862 + }
28.1863 +
28.1864 + /**
28.1865 + * Allows you to set the behavior of the decimal separator with integers.
28.1866 + * (The decimal separator will always appear with decimals.)
28.1867 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
28.1868 + */
28.1869 + public void setDecimalSeparatorAlwaysShown(boolean newValue) {
28.1870 + decimalSeparatorAlwaysShown = newValue;
28.1871 + }
28.1872 +
28.1873 + /**
28.1874 + * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
28.1875 + * method returns <code>BigDecimal</code>. The default value is false.
28.1876 + * @see #setParseBigDecimal
28.1877 + * @since 1.5
28.1878 + */
28.1879 + public boolean isParseBigDecimal() {
28.1880 + return parseBigDecimal;
28.1881 + }
28.1882 +
28.1883 + /**
28.1884 + * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
28.1885 + * method returns <code>BigDecimal</code>.
28.1886 + * @see #isParseBigDecimal
28.1887 + * @since 1.5
28.1888 + */
28.1889 + public void setParseBigDecimal(boolean newValue) {
28.1890 + parseBigDecimal = newValue;
28.1891 + }
28.1892 +
28.1893 + /**
28.1894 + * Standard override; no change in semantics.
28.1895 + */
28.1896 + public Object clone() {
28.1897 + try {
28.1898 + DecimalFormat other = (DecimalFormat) super.clone();
28.1899 + other.symbols = (DecimalFormatSymbols) symbols.clone();
28.1900 + other.digitList = (DigitList) digitList.clone();
28.1901 + return other;
28.1902 + } catch (Exception e) {
28.1903 + throw new InternalError();
28.1904 + }
28.1905 + }
28.1906 +
28.1907 + /**
28.1908 + * Overrides equals
28.1909 + */
28.1910 + public boolean equals(Object obj)
28.1911 + {
28.1912 + if (obj == null) return false;
28.1913 + if (!super.equals(obj)) return false; // super does class check
28.1914 + DecimalFormat other = (DecimalFormat) obj;
28.1915 + return ((posPrefixPattern == other.posPrefixPattern &&
28.1916 + positivePrefix.equals(other.positivePrefix))
28.1917 + || (posPrefixPattern != null &&
28.1918 + posPrefixPattern.equals(other.posPrefixPattern)))
28.1919 + && ((posSuffixPattern == other.posSuffixPattern &&
28.1920 + positiveSuffix.equals(other.positiveSuffix))
28.1921 + || (posSuffixPattern != null &&
28.1922 + posSuffixPattern.equals(other.posSuffixPattern)))
28.1923 + && ((negPrefixPattern == other.negPrefixPattern &&
28.1924 + negativePrefix.equals(other.negativePrefix))
28.1925 + || (negPrefixPattern != null &&
28.1926 + negPrefixPattern.equals(other.negPrefixPattern)))
28.1927 + && ((negSuffixPattern == other.negSuffixPattern &&
28.1928 + negativeSuffix.equals(other.negativeSuffix))
28.1929 + || (negSuffixPattern != null &&
28.1930 + negSuffixPattern.equals(other.negSuffixPattern)))
28.1931 + && multiplier == other.multiplier
28.1932 + && groupingSize == other.groupingSize
28.1933 + && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
28.1934 + && parseBigDecimal == other.parseBigDecimal
28.1935 + && useExponentialNotation == other.useExponentialNotation
28.1936 + && (!useExponentialNotation ||
28.1937 + minExponentDigits == other.minExponentDigits)
28.1938 + && maximumIntegerDigits == other.maximumIntegerDigits
28.1939 + && minimumIntegerDigits == other.minimumIntegerDigits
28.1940 + && maximumFractionDigits == other.maximumFractionDigits
28.1941 + && minimumFractionDigits == other.minimumFractionDigits
28.1942 + && roundingMode == other.roundingMode
28.1943 + && symbols.equals(other.symbols);
28.1944 + }
28.1945 +
28.1946 + /**
28.1947 + * Overrides hashCode
28.1948 + */
28.1949 + public int hashCode() {
28.1950 + return super.hashCode() * 37 + positivePrefix.hashCode();
28.1951 + // just enough fields for a reasonable distribution
28.1952 + }
28.1953 +
28.1954 + /**
28.1955 + * Synthesizes a pattern string that represents the current state
28.1956 + * of this Format object.
28.1957 + * @see #applyPattern
28.1958 + */
28.1959 + public String toPattern() {
28.1960 + return toPattern( false );
28.1961 + }
28.1962 +
28.1963 + /**
28.1964 + * Synthesizes a localized pattern string that represents the current
28.1965 + * state of this Format object.
28.1966 + * @see #applyPattern
28.1967 + */
28.1968 + public String toLocalizedPattern() {
28.1969 + return toPattern( true );
28.1970 + }
28.1971 +
28.1972 + /**
28.1973 + * Expand the affix pattern strings into the expanded affix strings. If any
28.1974 + * affix pattern string is null, do not expand it. This method should be
28.1975 + * called any time the symbols or the affix patterns change in order to keep
28.1976 + * the expanded affix strings up to date.
28.1977 + */
28.1978 + private void expandAffixes() {
28.1979 + // Reuse one StringBuffer for better performance
28.1980 + StringBuffer buffer = new StringBuffer();
28.1981 + if (posPrefixPattern != null) {
28.1982 + positivePrefix = expandAffix(posPrefixPattern, buffer);
28.1983 + positivePrefixFieldPositions = null;
28.1984 + }
28.1985 + if (posSuffixPattern != null) {
28.1986 + positiveSuffix = expandAffix(posSuffixPattern, buffer);
28.1987 + positiveSuffixFieldPositions = null;
28.1988 + }
28.1989 + if (negPrefixPattern != null) {
28.1990 + negativePrefix = expandAffix(negPrefixPattern, buffer);
28.1991 + negativePrefixFieldPositions = null;
28.1992 + }
28.1993 + if (negSuffixPattern != null) {
28.1994 + negativeSuffix = expandAffix(negSuffixPattern, buffer);
28.1995 + negativeSuffixFieldPositions = null;
28.1996 + }
28.1997 + }
28.1998 +
28.1999 + /**
28.2000 + * Expand an affix pattern into an affix string. All characters in the
28.2001 + * pattern are literal unless prefixed by QUOTE. The following characters
28.2002 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
28.2003 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
28.2004 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
28.2005 + * currency code. Any other character after a QUOTE represents itself.
28.2006 + * QUOTE must be followed by another character; QUOTE may not occur by
28.2007 + * itself at the end of the pattern.
28.2008 + *
28.2009 + * @param pattern the non-null, possibly empty pattern
28.2010 + * @param buffer a scratch StringBuffer; its contents will be lost
28.2011 + * @return the expanded equivalent of pattern
28.2012 + */
28.2013 + private String expandAffix(String pattern, StringBuffer buffer) {
28.2014 + buffer.setLength(0);
28.2015 + for (int i=0; i<pattern.length(); ) {
28.2016 + char c = pattern.charAt(i++);
28.2017 + if (c == QUOTE) {
28.2018 + c = pattern.charAt(i++);
28.2019 + switch (c) {
28.2020 + case CURRENCY_SIGN:
28.2021 + if (i<pattern.length() &&
28.2022 + pattern.charAt(i) == CURRENCY_SIGN) {
28.2023 + ++i;
28.2024 + buffer.append(symbols.getInternationalCurrencySymbol());
28.2025 + } else {
28.2026 + buffer.append(symbols.getCurrencySymbol());
28.2027 + }
28.2028 + continue;
28.2029 + case PATTERN_PERCENT:
28.2030 + c = symbols.getPercent();
28.2031 + break;
28.2032 + case PATTERN_PER_MILLE:
28.2033 + c = symbols.getPerMill();
28.2034 + break;
28.2035 + case PATTERN_MINUS:
28.2036 + c = symbols.getMinusSign();
28.2037 + break;
28.2038 + }
28.2039 + }
28.2040 + buffer.append(c);
28.2041 + }
28.2042 + return buffer.toString();
28.2043 + }
28.2044 +
28.2045 + /**
28.2046 + * Expand an affix pattern into an array of FieldPositions describing
28.2047 + * how the pattern would be expanded.
28.2048 + * All characters in the
28.2049 + * pattern are literal unless prefixed by QUOTE. The following characters
28.2050 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
28.2051 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
28.2052 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
28.2053 + * currency code. Any other character after a QUOTE represents itself.
28.2054 + * QUOTE must be followed by another character; QUOTE may not occur by
28.2055 + * itself at the end of the pattern.
28.2056 + *
28.2057 + * @param pattern the non-null, possibly empty pattern
28.2058 + * @return FieldPosition array of the resulting fields.
28.2059 + */
28.2060 + private FieldPosition[] expandAffix(String pattern) {
28.2061 + ArrayList positions = null;
28.2062 + int stringIndex = 0;
28.2063 + for (int i=0; i<pattern.length(); ) {
28.2064 + char c = pattern.charAt(i++);
28.2065 + if (c == QUOTE) {
28.2066 + int field = -1;
28.2067 + Format.Field fieldID = null;
28.2068 + c = pattern.charAt(i++);
28.2069 + switch (c) {
28.2070 + case CURRENCY_SIGN:
28.2071 + String string;
28.2072 + if (i<pattern.length() &&
28.2073 + pattern.charAt(i) == CURRENCY_SIGN) {
28.2074 + ++i;
28.2075 + string = symbols.getInternationalCurrencySymbol();
28.2076 + } else {
28.2077 + string = symbols.getCurrencySymbol();
28.2078 + }
28.2079 + if (string.length() > 0) {
28.2080 + if (positions == null) {
28.2081 + positions = new ArrayList(2);
28.2082 + }
28.2083 + FieldPosition fp = new FieldPosition(Field.CURRENCY);
28.2084 + fp.setBeginIndex(stringIndex);
28.2085 + fp.setEndIndex(stringIndex + string.length());
28.2086 + positions.add(fp);
28.2087 + stringIndex += string.length();
28.2088 + }
28.2089 + continue;
28.2090 + case PATTERN_PERCENT:
28.2091 + c = symbols.getPercent();
28.2092 + field = -1;
28.2093 + fieldID = Field.PERCENT;
28.2094 + break;
28.2095 + case PATTERN_PER_MILLE:
28.2096 + c = symbols.getPerMill();
28.2097 + field = -1;
28.2098 + fieldID = Field.PERMILLE;
28.2099 + break;
28.2100 + case PATTERN_MINUS:
28.2101 + c = symbols.getMinusSign();
28.2102 + field = -1;
28.2103 + fieldID = Field.SIGN;
28.2104 + break;
28.2105 + }
28.2106 + if (fieldID != null) {
28.2107 + if (positions == null) {
28.2108 + positions = new ArrayList(2);
28.2109 + }
28.2110 + FieldPosition fp = new FieldPosition(fieldID, field);
28.2111 + fp.setBeginIndex(stringIndex);
28.2112 + fp.setEndIndex(stringIndex + 1);
28.2113 + positions.add(fp);
28.2114 + }
28.2115 + }
28.2116 + stringIndex++;
28.2117 + }
28.2118 + if (positions != null) {
28.2119 + return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
28.2120 + }
28.2121 + return EmptyFieldPositionArray;
28.2122 + }
28.2123 +
28.2124 + /**
28.2125 + * Appends an affix pattern to the given StringBuffer, quoting special
28.2126 + * characters as needed. Uses the internal affix pattern, if that exists,
28.2127 + * or the literal affix, if the internal affix pattern is null. The
28.2128 + * appended string will generate the same affix pattern (or literal affix)
28.2129 + * when passed to toPattern().
28.2130 + *
28.2131 + * @param buffer the affix string is appended to this
28.2132 + * @param affixPattern a pattern such as posPrefixPattern; may be null
28.2133 + * @param expAffix a corresponding expanded affix, such as positivePrefix.
28.2134 + * Ignored unless affixPattern is null. If affixPattern is null, then
28.2135 + * expAffix is appended as a literal affix.
28.2136 + * @param localized true if the appended pattern should contain localized
28.2137 + * pattern characters; otherwise, non-localized pattern chars are appended
28.2138 + */
28.2139 + private void appendAffix(StringBuffer buffer, String affixPattern,
28.2140 + String expAffix, boolean localized) {
28.2141 + if (affixPattern == null) {
28.2142 + appendAffix(buffer, expAffix, localized);
28.2143 + } else {
28.2144 + int i;
28.2145 + for (int pos=0; pos<affixPattern.length(); pos=i) {
28.2146 + i = affixPattern.indexOf(QUOTE, pos);
28.2147 + if (i < 0) {
28.2148 + appendAffix(buffer, affixPattern.substring(pos), localized);
28.2149 + break;
28.2150 + }
28.2151 + if (i > pos) {
28.2152 + appendAffix(buffer, affixPattern.substring(pos, i), localized);
28.2153 + }
28.2154 + char c = affixPattern.charAt(++i);
28.2155 + ++i;
28.2156 + if (c == QUOTE) {
28.2157 + buffer.append(c);
28.2158 + // Fall through and append another QUOTE below
28.2159 + } else if (c == CURRENCY_SIGN &&
28.2160 + i<affixPattern.length() &&
28.2161 + affixPattern.charAt(i) == CURRENCY_SIGN) {
28.2162 + ++i;
28.2163 + buffer.append(c);
28.2164 + // Fall through and append another CURRENCY_SIGN below
28.2165 + } else if (localized) {
28.2166 + switch (c) {
28.2167 + case PATTERN_PERCENT:
28.2168 + c = symbols.getPercent();
28.2169 + break;
28.2170 + case PATTERN_PER_MILLE:
28.2171 + c = symbols.getPerMill();
28.2172 + break;
28.2173 + case PATTERN_MINUS:
28.2174 + c = symbols.getMinusSign();
28.2175 + break;
28.2176 + }
28.2177 + }
28.2178 + buffer.append(c);
28.2179 + }
28.2180 + }
28.2181 + }
28.2182 +
28.2183 + /**
28.2184 + * Append an affix to the given StringBuffer, using quotes if
28.2185 + * there are special characters. Single quotes themselves must be
28.2186 + * escaped in either case.
28.2187 + */
28.2188 + private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
28.2189 + boolean needQuote;
28.2190 + if (localized) {
28.2191 + needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
28.2192 + || affix.indexOf(symbols.getGroupingSeparator()) >= 0
28.2193 + || affix.indexOf(symbols.getDecimalSeparator()) >= 0
28.2194 + || affix.indexOf(symbols.getPercent()) >= 0
28.2195 + || affix.indexOf(symbols.getPerMill()) >= 0
28.2196 + || affix.indexOf(symbols.getDigit()) >= 0
28.2197 + || affix.indexOf(symbols.getPatternSeparator()) >= 0
28.2198 + || affix.indexOf(symbols.getMinusSign()) >= 0
28.2199 + || affix.indexOf(CURRENCY_SIGN) >= 0;
28.2200 + }
28.2201 + else {
28.2202 + needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
28.2203 + || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
28.2204 + || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
28.2205 + || affix.indexOf(PATTERN_PERCENT) >= 0
28.2206 + || affix.indexOf(PATTERN_PER_MILLE) >= 0
28.2207 + || affix.indexOf(PATTERN_DIGIT) >= 0
28.2208 + || affix.indexOf(PATTERN_SEPARATOR) >= 0
28.2209 + || affix.indexOf(PATTERN_MINUS) >= 0
28.2210 + || affix.indexOf(CURRENCY_SIGN) >= 0;
28.2211 + }
28.2212 + if (needQuote) buffer.append('\'');
28.2213 + if (affix.indexOf('\'') < 0) buffer.append(affix);
28.2214 + else {
28.2215 + for (int j=0; j<affix.length(); ++j) {
28.2216 + char c = affix.charAt(j);
28.2217 + buffer.append(c);
28.2218 + if (c == '\'') buffer.append(c);
28.2219 + }
28.2220 + }
28.2221 + if (needQuote) buffer.append('\'');
28.2222 + }
28.2223 +
28.2224 + /**
28.2225 + * Does the real work of generating a pattern. */
28.2226 + private String toPattern(boolean localized) {
28.2227 + StringBuffer result = new StringBuffer();
28.2228 + for (int j = 1; j >= 0; --j) {
28.2229 + if (j == 1)
28.2230 + appendAffix(result, posPrefixPattern, positivePrefix, localized);
28.2231 + else appendAffix(result, negPrefixPattern, negativePrefix, localized);
28.2232 + int i;
28.2233 + int digitCount = useExponentialNotation
28.2234 + ? getMaximumIntegerDigits()
28.2235 + : Math.max(groupingSize, getMinimumIntegerDigits())+1;
28.2236 + for (i = digitCount; i > 0; --i) {
28.2237 + if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
28.2238 + i % groupingSize == 0) {
28.2239 + result.append(localized ? symbols.getGroupingSeparator() :
28.2240 + PATTERN_GROUPING_SEPARATOR);
28.2241 + }
28.2242 + result.append(i <= getMinimumIntegerDigits()
28.2243 + ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
28.2244 + : (localized ? symbols.getDigit() : PATTERN_DIGIT));
28.2245 + }
28.2246 + if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
28.2247 + result.append(localized ? symbols.getDecimalSeparator() :
28.2248 + PATTERN_DECIMAL_SEPARATOR);
28.2249 + for (i = 0; i < getMaximumFractionDigits(); ++i) {
28.2250 + if (i < getMinimumFractionDigits()) {
28.2251 + result.append(localized ? symbols.getZeroDigit() :
28.2252 + PATTERN_ZERO_DIGIT);
28.2253 + } else {
28.2254 + result.append(localized ? symbols.getDigit() :
28.2255 + PATTERN_DIGIT);
28.2256 + }
28.2257 + }
28.2258 + if (useExponentialNotation)
28.2259 + {
28.2260 + result.append(localized ? symbols.getExponentSeparator() :
28.2261 + PATTERN_EXPONENT);
28.2262 + for (i=0; i<minExponentDigits; ++i)
28.2263 + result.append(localized ? symbols.getZeroDigit() :
28.2264 + PATTERN_ZERO_DIGIT);
28.2265 + }
28.2266 + if (j == 1) {
28.2267 + appendAffix(result, posSuffixPattern, positiveSuffix, localized);
28.2268 + if ((negSuffixPattern == posSuffixPattern && // n == p == null
28.2269 + negativeSuffix.equals(positiveSuffix))
28.2270 + || (negSuffixPattern != null &&
28.2271 + negSuffixPattern.equals(posSuffixPattern))) {
28.2272 + if ((negPrefixPattern != null && posPrefixPattern != null &&
28.2273 + negPrefixPattern.equals("'-" + posPrefixPattern)) ||
28.2274 + (negPrefixPattern == posPrefixPattern && // n == p == null
28.2275 + negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
28.2276 + break;
28.2277 + }
28.2278 + result.append(localized ? symbols.getPatternSeparator() :
28.2279 + PATTERN_SEPARATOR);
28.2280 + } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
28.2281 + }
28.2282 + return result.toString();
28.2283 + }
28.2284 +
28.2285 + /**
28.2286 + * Apply the given pattern to this Format object. A pattern is a
28.2287 + * short-hand specification for the various formatting properties.
28.2288 + * These properties can also be changed individually through the
28.2289 + * various setter methods.
28.2290 + * <p>
28.2291 + * There is no limit to integer digits set
28.2292 + * by this routine, since that is the typical end-user desire;
28.2293 + * use setMaximumInteger if you want to set a real value.
28.2294 + * For negative numbers, use a second pattern, separated by a semicolon
28.2295 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
28.2296 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
28.2297 + * a maximum of 2 fraction digits.
28.2298 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
28.2299 + * parentheses.
28.2300 + * <p>In negative patterns, the minimum and maximum counts are ignored;
28.2301 + * these are presumed to be set in the positive pattern.
28.2302 + *
28.2303 + * @exception NullPointerException if <code>pattern</code> is null
28.2304 + * @exception IllegalArgumentException if the given pattern is invalid.
28.2305 + */
28.2306 + public void applyPattern(String pattern) {
28.2307 + applyPattern(pattern, false);
28.2308 + }
28.2309 +
28.2310 + /**
28.2311 + * Apply the given pattern to this Format object. The pattern
28.2312 + * is assumed to be in a localized notation. A pattern is a
28.2313 + * short-hand specification for the various formatting properties.
28.2314 + * These properties can also be changed individually through the
28.2315 + * various setter methods.
28.2316 + * <p>
28.2317 + * There is no limit to integer digits set
28.2318 + * by this routine, since that is the typical end-user desire;
28.2319 + * use setMaximumInteger if you want to set a real value.
28.2320 + * For negative numbers, use a second pattern, separated by a semicolon
28.2321 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
28.2322 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
28.2323 + * a maximum of 2 fraction digits.
28.2324 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
28.2325 + * parentheses.
28.2326 + * <p>In negative patterns, the minimum and maximum counts are ignored;
28.2327 + * these are presumed to be set in the positive pattern.
28.2328 + *
28.2329 + * @exception NullPointerException if <code>pattern</code> is null
28.2330 + * @exception IllegalArgumentException if the given pattern is invalid.
28.2331 + */
28.2332 + public void applyLocalizedPattern(String pattern) {
28.2333 + applyPattern(pattern, true);
28.2334 + }
28.2335 +
28.2336 + /**
28.2337 + * Does the real work of applying a pattern.
28.2338 + */
28.2339 + private void applyPattern(String pattern, boolean localized) {
28.2340 + char zeroDigit = PATTERN_ZERO_DIGIT;
28.2341 + char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
28.2342 + char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
28.2343 + char percent = PATTERN_PERCENT;
28.2344 + char perMill = PATTERN_PER_MILLE;
28.2345 + char digit = PATTERN_DIGIT;
28.2346 + char separator = PATTERN_SEPARATOR;
28.2347 + String exponent = PATTERN_EXPONENT;
28.2348 + char minus = PATTERN_MINUS;
28.2349 + if (localized) {
28.2350 + zeroDigit = symbols.getZeroDigit();
28.2351 + groupingSeparator = symbols.getGroupingSeparator();
28.2352 + decimalSeparator = symbols.getDecimalSeparator();
28.2353 + percent = symbols.getPercent();
28.2354 + perMill = symbols.getPerMill();
28.2355 + digit = symbols.getDigit();
28.2356 + separator = symbols.getPatternSeparator();
28.2357 + exponent = symbols.getExponentSeparator();
28.2358 + minus = symbols.getMinusSign();
28.2359 + }
28.2360 + boolean gotNegative = false;
28.2361 + decimalSeparatorAlwaysShown = false;
28.2362 + isCurrencyFormat = false;
28.2363 + useExponentialNotation = false;
28.2364 +
28.2365 + // Two variables are used to record the subrange of the pattern
28.2366 + // occupied by phase 1. This is used during the processing of the
28.2367 + // second pattern (the one representing negative numbers) to ensure
28.2368 + // that no deviation exists in phase 1 between the two patterns.
28.2369 + int phaseOneStart = 0;
28.2370 + int phaseOneLength = 0;
28.2371 +
28.2372 + int start = 0;
28.2373 + for (int j = 1; j >= 0 && start < pattern.length(); --j) {
28.2374 + boolean inQuote = false;
28.2375 + StringBuffer prefix = new StringBuffer();
28.2376 + StringBuffer suffix = new StringBuffer();
28.2377 + int decimalPos = -1;
28.2378 + int multiplier = 1;
28.2379 + int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
28.2380 + byte groupingCount = -1;
28.2381 +
28.2382 + // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is
28.2383 + // the section of the pattern with digits, decimal separator,
28.2384 + // grouping characters. Phase 2 is the suffix. In phases 0 and 2,
28.2385 + // percent, per mille, and currency symbols are recognized and
28.2386 + // translated. The separation of the characters into phases is
28.2387 + // strictly enforced; if phase 1 characters are to appear in the
28.2388 + // suffix, for example, they must be quoted.
28.2389 + int phase = 0;
28.2390 +
28.2391 + // The affix is either the prefix or the suffix.
28.2392 + StringBuffer affix = prefix;
28.2393 +
28.2394 + for (int pos = start; pos < pattern.length(); ++pos) {
28.2395 + char ch = pattern.charAt(pos);
28.2396 + switch (phase) {
28.2397 + case 0:
28.2398 + case 2:
28.2399 + // Process the prefix / suffix characters
28.2400 + if (inQuote) {
28.2401 + // A quote within quotes indicates either the closing
28.2402 + // quote or two quotes, which is a quote literal. That
28.2403 + // is, we have the second quote in 'do' or 'don''t'.
28.2404 + if (ch == QUOTE) {
28.2405 + if ((pos+1) < pattern.length() &&
28.2406 + pattern.charAt(pos+1) == QUOTE) {
28.2407 + ++pos;
28.2408 + affix.append("''"); // 'don''t'
28.2409 + } else {
28.2410 + inQuote = false; // 'do'
28.2411 + }
28.2412 + continue;
28.2413 + }
28.2414 + } else {
28.2415 + // Process unquoted characters seen in prefix or suffix
28.2416 + // phase.
28.2417 + if (ch == digit ||
28.2418 + ch == zeroDigit ||
28.2419 + ch == groupingSeparator ||
28.2420 + ch == decimalSeparator) {
28.2421 + phase = 1;
28.2422 + if (j == 1) {
28.2423 + phaseOneStart = pos;
28.2424 + }
28.2425 + --pos; // Reprocess this character
28.2426 + continue;
28.2427 + } else if (ch == CURRENCY_SIGN) {
28.2428 + // Use lookahead to determine if the currency sign
28.2429 + // is doubled or not.
28.2430 + boolean doubled = (pos + 1) < pattern.length() &&
28.2431 + pattern.charAt(pos + 1) == CURRENCY_SIGN;
28.2432 + if (doubled) { // Skip over the doubled character
28.2433 + ++pos;
28.2434 + }
28.2435 + isCurrencyFormat = true;
28.2436 + affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
28.2437 + continue;
28.2438 + } else if (ch == QUOTE) {
28.2439 + // A quote outside quotes indicates either the
28.2440 + // opening quote or two quotes, which is a quote
28.2441 + // literal. That is, we have the first quote in 'do'
28.2442 + // or o''clock.
28.2443 + if (ch == QUOTE) {
28.2444 + if ((pos+1) < pattern.length() &&
28.2445 + pattern.charAt(pos+1) == QUOTE) {
28.2446 + ++pos;
28.2447 + affix.append("''"); // o''clock
28.2448 + } else {
28.2449 + inQuote = true; // 'do'
28.2450 + }
28.2451 + continue;
28.2452 + }
28.2453 + } else if (ch == separator) {
28.2454 + // Don't allow separators before we see digit
28.2455 + // characters of phase 1, and don't allow separators
28.2456 + // in the second pattern (j == 0).
28.2457 + if (phase == 0 || j == 0) {
28.2458 + throw new IllegalArgumentException("Unquoted special character '" +
28.2459 + ch + "' in pattern \"" + pattern + '"');
28.2460 + }
28.2461 + start = pos + 1;
28.2462 + pos = pattern.length();
28.2463 + continue;
28.2464 + }
28.2465 +
28.2466 + // Next handle characters which are appended directly.
28.2467 + else if (ch == percent) {
28.2468 + if (multiplier != 1) {
28.2469 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
28.2470 + pattern + '"');
28.2471 + }
28.2472 + multiplier = 100;
28.2473 + affix.append("'%");
28.2474 + continue;
28.2475 + } else if (ch == perMill) {
28.2476 + if (multiplier != 1) {
28.2477 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
28.2478 + pattern + '"');
28.2479 + }
28.2480 + multiplier = 1000;
28.2481 + affix.append("'\u2030");
28.2482 + continue;
28.2483 + } else if (ch == minus) {
28.2484 + affix.append("'-");
28.2485 + continue;
28.2486 + }
28.2487 + }
28.2488 + // Note that if we are within quotes, or if this is an
28.2489 + // unquoted, non-special character, then we usually fall
28.2490 + // through to here.
28.2491 + affix.append(ch);
28.2492 + break;
28.2493 +
28.2494 + case 1:
28.2495 + // Phase one must be identical in the two sub-patterns. We
28.2496 + // enforce this by doing a direct comparison. While
28.2497 + // processing the first sub-pattern, we just record its
28.2498 + // length. While processing the second, we compare
28.2499 + // characters.
28.2500 + if (j == 1) {
28.2501 + ++phaseOneLength;
28.2502 + } else {
28.2503 + if (--phaseOneLength == 0) {
28.2504 + phase = 2;
28.2505 + affix = suffix;
28.2506 + }
28.2507 + continue;
28.2508 + }
28.2509 +
28.2510 + // Process the digits, decimal, and grouping characters. We
28.2511 + // record five pieces of information. We expect the digits
28.2512 + // to occur in the pattern ####0000.####, and we record the
28.2513 + // number of left digits, zero (central) digits, and right
28.2514 + // digits. The position of the last grouping character is
28.2515 + // recorded (should be somewhere within the first two blocks
28.2516 + // of characters), as is the position of the decimal point,
28.2517 + // if any (should be in the zero digits). If there is no
28.2518 + // decimal point, then there should be no right digits.
28.2519 + if (ch == digit) {
28.2520 + if (zeroDigitCount > 0) {
28.2521 + ++digitRightCount;
28.2522 + } else {
28.2523 + ++digitLeftCount;
28.2524 + }
28.2525 + if (groupingCount >= 0 && decimalPos < 0) {
28.2526 + ++groupingCount;
28.2527 + }
28.2528 + } else if (ch == zeroDigit) {
28.2529 + if (digitRightCount > 0) {
28.2530 + throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
28.2531 + pattern + '"');
28.2532 + }
28.2533 + ++zeroDigitCount;
28.2534 + if (groupingCount >= 0 && decimalPos < 0) {
28.2535 + ++groupingCount;
28.2536 + }
28.2537 + } else if (ch == groupingSeparator) {
28.2538 + groupingCount = 0;
28.2539 + } else if (ch == decimalSeparator) {
28.2540 + if (decimalPos >= 0) {
28.2541 + throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
28.2542 + pattern + '"');
28.2543 + }
28.2544 + decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
28.2545 + } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
28.2546 + if (useExponentialNotation) {
28.2547 + throw new IllegalArgumentException("Multiple exponential " +
28.2548 + "symbols in pattern \"" + pattern + '"');
28.2549 + }
28.2550 + useExponentialNotation = true;
28.2551 + minExponentDigits = 0;
28.2552 +
28.2553 + // Use lookahead to parse out the exponential part
28.2554 + // of the pattern, then jump into phase 2.
28.2555 + pos = pos+exponent.length();
28.2556 + while (pos < pattern.length() &&
28.2557 + pattern.charAt(pos) == zeroDigit) {
28.2558 + ++minExponentDigits;
28.2559 + ++phaseOneLength;
28.2560 + ++pos;
28.2561 + }
28.2562 +
28.2563 + if ((digitLeftCount + zeroDigitCount) < 1 ||
28.2564 + minExponentDigits < 1) {
28.2565 + throw new IllegalArgumentException("Malformed exponential " +
28.2566 + "pattern \"" + pattern + '"');
28.2567 + }
28.2568 +
28.2569 + // Transition to phase 2
28.2570 + phase = 2;
28.2571 + affix = suffix;
28.2572 + --pos;
28.2573 + continue;
28.2574 + } else {
28.2575 + phase = 2;
28.2576 + affix = suffix;
28.2577 + --pos;
28.2578 + --phaseOneLength;
28.2579 + continue;
28.2580 + }
28.2581 + break;
28.2582 + }
28.2583 + }
28.2584 +
28.2585 + // Handle patterns with no '0' pattern character. These patterns
28.2586 + // are legal, but must be interpreted. "##.###" -> "#0.###".
28.2587 + // ".###" -> ".0##".
28.2588 + /* We allow patterns of the form "####" to produce a zeroDigitCount
28.2589 + * of zero (got that?); although this seems like it might make it
28.2590 + * possible for format() to produce empty strings, format() checks
28.2591 + * for this condition and outputs a zero digit in this situation.
28.2592 + * Having a zeroDigitCount of zero yields a minimum integer digits
28.2593 + * of zero, which allows proper round-trip patterns. That is, we
28.2594 + * don't want "#" to become "#0" when toPattern() is called (even
28.2595 + * though that's what it really is, semantically).
28.2596 + */
28.2597 + if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
28.2598 + // Handle "###.###" and "###." and ".###"
28.2599 + int n = decimalPos;
28.2600 + if (n == 0) { // Handle ".###"
28.2601 + ++n;
28.2602 + }
28.2603 + digitRightCount = digitLeftCount - n;
28.2604 + digitLeftCount = n - 1;
28.2605 + zeroDigitCount = 1;
28.2606 + }
28.2607 +
28.2608 + // Do syntax checking on the digits.
28.2609 + if ((decimalPos < 0 && digitRightCount > 0) ||
28.2610 + (decimalPos >= 0 && (decimalPos < digitLeftCount ||
28.2611 + decimalPos > (digitLeftCount + zeroDigitCount))) ||
28.2612 + groupingCount == 0 || inQuote) {
28.2613 + throw new IllegalArgumentException("Malformed pattern \"" +
28.2614 + pattern + '"');
28.2615 + }
28.2616 +
28.2617 + if (j == 1) {
28.2618 + posPrefixPattern = prefix.toString();
28.2619 + posSuffixPattern = suffix.toString();
28.2620 + negPrefixPattern = posPrefixPattern; // assume these for now
28.2621 + negSuffixPattern = posSuffixPattern;
28.2622 + int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
28.2623 + /* The effectiveDecimalPos is the position the decimal is at or
28.2624 + * would be at if there is no decimal. Note that if decimalPos<0,
28.2625 + * then digitTotalCount == digitLeftCount + zeroDigitCount.
28.2626 + */
28.2627 + int effectiveDecimalPos = decimalPos >= 0 ?
28.2628 + decimalPos : digitTotalCount;
28.2629 + setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
28.2630 + setMaximumIntegerDigits(useExponentialNotation ?
28.2631 + digitLeftCount + getMinimumIntegerDigits() :
28.2632 + MAXIMUM_INTEGER_DIGITS);
28.2633 + setMaximumFractionDigits(decimalPos >= 0 ?
28.2634 + (digitTotalCount - decimalPos) : 0);
28.2635 + setMinimumFractionDigits(decimalPos >= 0 ?
28.2636 + (digitLeftCount + zeroDigitCount - decimalPos) : 0);
28.2637 + setGroupingUsed(groupingCount > 0);
28.2638 + this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
28.2639 + this.multiplier = multiplier;
28.2640 + setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
28.2641 + decimalPos == digitTotalCount);
28.2642 + } else {
28.2643 + negPrefixPattern = prefix.toString();
28.2644 + negSuffixPattern = suffix.toString();
28.2645 + gotNegative = true;
28.2646 + }
28.2647 + }
28.2648 +
28.2649 + if (pattern.length() == 0) {
28.2650 + posPrefixPattern = posSuffixPattern = "";
28.2651 + setMinimumIntegerDigits(0);
28.2652 + setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
28.2653 + setMinimumFractionDigits(0);
28.2654 + setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
28.2655 + }
28.2656 +
28.2657 + // If there was no negative pattern, or if the negative pattern is
28.2658 + // identical to the positive pattern, then prepend the minus sign to
28.2659 + // the positive pattern to form the negative pattern.
28.2660 + if (!gotNegative ||
28.2661 + (negPrefixPattern.equals(posPrefixPattern)
28.2662 + && negSuffixPattern.equals(posSuffixPattern))) {
28.2663 + negSuffixPattern = posSuffixPattern;
28.2664 + negPrefixPattern = "'-" + posPrefixPattern;
28.2665 + }
28.2666 +
28.2667 + expandAffixes();
28.2668 + }
28.2669 +
28.2670 + /**
28.2671 + * Sets the maximum number of digits allowed in the integer portion of a
28.2672 + * number.
28.2673 + * For formatting numbers other than <code>BigInteger</code> and
28.2674 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
28.2675 + * 309 is used. Negative input values are replaced with 0.
28.2676 + * @see NumberFormat#setMaximumIntegerDigits
28.2677 + */
28.2678 + public void setMaximumIntegerDigits(int newValue) {
28.2679 + maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
28.2680 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
28.2681 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
28.2682 + if (minimumIntegerDigits > maximumIntegerDigits) {
28.2683 + minimumIntegerDigits = maximumIntegerDigits;
28.2684 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
28.2685 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
28.2686 + }
28.2687 + }
28.2688 +
28.2689 + /**
28.2690 + * Sets the minimum number of digits allowed in the integer portion of a
28.2691 + * number.
28.2692 + * For formatting numbers other than <code>BigInteger</code> and
28.2693 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
28.2694 + * 309 is used. Negative input values are replaced with 0.
28.2695 + * @see NumberFormat#setMinimumIntegerDigits
28.2696 + */
28.2697 + public void setMinimumIntegerDigits(int newValue) {
28.2698 + minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
28.2699 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
28.2700 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
28.2701 + if (minimumIntegerDigits > maximumIntegerDigits) {
28.2702 + maximumIntegerDigits = minimumIntegerDigits;
28.2703 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
28.2704 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
28.2705 + }
28.2706 + }
28.2707 +
28.2708 + /**
28.2709 + * Sets the maximum number of digits allowed in the fraction portion of a
28.2710 + * number.
28.2711 + * For formatting numbers other than <code>BigInteger</code> and
28.2712 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
28.2713 + * 340 is used. Negative input values are replaced with 0.
28.2714 + * @see NumberFormat#setMaximumFractionDigits
28.2715 + */
28.2716 + public void setMaximumFractionDigits(int newValue) {
28.2717 + maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
28.2718 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
28.2719 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
28.2720 + if (minimumFractionDigits > maximumFractionDigits) {
28.2721 + minimumFractionDigits = maximumFractionDigits;
28.2722 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
28.2723 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
28.2724 + }
28.2725 + }
28.2726 +
28.2727 + /**
28.2728 + * Sets the minimum number of digits allowed in the fraction portion of a
28.2729 + * number.
28.2730 + * For formatting numbers other than <code>BigInteger</code> and
28.2731 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
28.2732 + * 340 is used. Negative input values are replaced with 0.
28.2733 + * @see NumberFormat#setMinimumFractionDigits
28.2734 + */
28.2735 + public void setMinimumFractionDigits(int newValue) {
28.2736 + minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
28.2737 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
28.2738 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
28.2739 + if (minimumFractionDigits > maximumFractionDigits) {
28.2740 + maximumFractionDigits = minimumFractionDigits;
28.2741 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
28.2742 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
28.2743 + }
28.2744 + }
28.2745 +
28.2746 + /**
28.2747 + * Gets the maximum number of digits allowed in the integer portion of a
28.2748 + * number.
28.2749 + * For formatting numbers other than <code>BigInteger</code> and
28.2750 + * <code>BigDecimal</code> objects, the lower of the return value and
28.2751 + * 309 is used.
28.2752 + * @see #setMaximumIntegerDigits
28.2753 + */
28.2754 + public int getMaximumIntegerDigits() {
28.2755 + return maximumIntegerDigits;
28.2756 + }
28.2757 +
28.2758 + /**
28.2759 + * Gets the minimum number of digits allowed in the integer portion of a
28.2760 + * number.
28.2761 + * For formatting numbers other than <code>BigInteger</code> and
28.2762 + * <code>BigDecimal</code> objects, the lower of the return value and
28.2763 + * 309 is used.
28.2764 + * @see #setMinimumIntegerDigits
28.2765 + */
28.2766 + public int getMinimumIntegerDigits() {
28.2767 + return minimumIntegerDigits;
28.2768 + }
28.2769 +
28.2770 + /**
28.2771 + * Gets the maximum number of digits allowed in the fraction portion of a
28.2772 + * number.
28.2773 + * For formatting numbers other than <code>BigInteger</code> and
28.2774 + * <code>BigDecimal</code> objects, the lower of the return value and
28.2775 + * 340 is used.
28.2776 + * @see #setMaximumFractionDigits
28.2777 + */
28.2778 + public int getMaximumFractionDigits() {
28.2779 + return maximumFractionDigits;
28.2780 + }
28.2781 +
28.2782 + /**
28.2783 + * Gets the minimum number of digits allowed in the fraction portion of a
28.2784 + * number.
28.2785 + * For formatting numbers other than <code>BigInteger</code> and
28.2786 + * <code>BigDecimal</code> objects, the lower of the return value and
28.2787 + * 340 is used.
28.2788 + * @see #setMinimumFractionDigits
28.2789 + */
28.2790 + public int getMinimumFractionDigits() {
28.2791 + return minimumFractionDigits;
28.2792 + }
28.2793 +
28.2794 + /**
28.2795 + * Gets the currency used by this decimal format when formatting
28.2796 + * currency values.
28.2797 + * The currency is obtained by calling
28.2798 + * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
28.2799 + * on this number format's symbols.
28.2800 + *
28.2801 + * @return the currency used by this decimal format, or <code>null</code>
28.2802 + * @since 1.4
28.2803 + */
28.2804 + public Currency getCurrency() {
28.2805 + return symbols.getCurrency();
28.2806 + }
28.2807 +
28.2808 + /**
28.2809 + * Sets the currency used by this number format when formatting
28.2810 + * currency values. This does not update the minimum or maximum
28.2811 + * number of fraction digits used by the number format.
28.2812 + * The currency is set by calling
28.2813 + * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
28.2814 + * on this number format's symbols.
28.2815 + *
28.2816 + * @param currency the new currency to be used by this decimal format
28.2817 + * @exception NullPointerException if <code>currency</code> is null
28.2818 + * @since 1.4
28.2819 + */
28.2820 + public void setCurrency(Currency currency) {
28.2821 + if (currency != symbols.getCurrency()) {
28.2822 + symbols.setCurrency(currency);
28.2823 + if (isCurrencyFormat) {
28.2824 + expandAffixes();
28.2825 + }
28.2826 + }
28.2827 + }
28.2828 +
28.2829 + /**
28.2830 + * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
28.2831 + *
28.2832 + * @return The <code>RoundingMode</code> used for this DecimalFormat.
28.2833 + * @see #setRoundingMode(RoundingMode)
28.2834 + * @since 1.6
28.2835 + */
28.2836 + public RoundingMode getRoundingMode() {
28.2837 + return roundingMode;
28.2838 + }
28.2839 +
28.2840 + /**
28.2841 + * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
28.2842 + *
28.2843 + * @param roundingMode The <code>RoundingMode</code> to be used
28.2844 + * @see #getRoundingMode()
28.2845 + * @exception NullPointerException if <code>roundingMode</code> is null.
28.2846 + * @since 1.6
28.2847 + */
28.2848 + public void setRoundingMode(RoundingMode roundingMode) {
28.2849 + if (roundingMode == null) {
28.2850 + throw new NullPointerException();
28.2851 + }
28.2852 +
28.2853 + this.roundingMode = roundingMode;
28.2854 + digitList.setRoundingMode(roundingMode);
28.2855 + }
28.2856 +
28.2857 + /**
28.2858 + * Adjusts the minimum and maximum fraction digits to values that
28.2859 + * are reasonable for the currency's default fraction digits.
28.2860 + */
28.2861 + void adjustForCurrencyDefaultFractionDigits() {
28.2862 + Currency currency = symbols.getCurrency();
28.2863 + if (currency == null) {
28.2864 + try {
28.2865 + currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
28.2866 + } catch (IllegalArgumentException e) {
28.2867 + }
28.2868 + }
28.2869 + if (currency != null) {
28.2870 + int digits = currency.getDefaultFractionDigits();
28.2871 + if (digits != -1) {
28.2872 + int oldMinDigits = getMinimumFractionDigits();
28.2873 + // Common patterns are "#.##", "#.00", "#".
28.2874 + // Try to adjust all of them in a reasonable way.
28.2875 + if (oldMinDigits == getMaximumFractionDigits()) {
28.2876 + setMinimumFractionDigits(digits);
28.2877 + setMaximumFractionDigits(digits);
28.2878 + } else {
28.2879 + setMinimumFractionDigits(Math.min(digits, oldMinDigits));
28.2880 + setMaximumFractionDigits(digits);
28.2881 + }
28.2882 + }
28.2883 + }
28.2884 + }
28.2885 +
28.2886 + /**
28.2887 + * Reads the default serializable fields from the stream and performs
28.2888 + * validations and adjustments for older serialized versions. The
28.2889 + * validations and adjustments are:
28.2890 + * <ol>
28.2891 + * <li>
28.2892 + * Verify that the superclass's digit count fields correctly reflect
28.2893 + * the limits imposed on formatting numbers other than
28.2894 + * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
28.2895 + * limits are stored in the superclass for serialization compatibility
28.2896 + * with older versions, while the limits for <code>BigInteger</code> and
28.2897 + * <code>BigDecimal</code> objects are kept in this class.
28.2898 + * If, in the superclass, the minimum or maximum integer digit count is
28.2899 + * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
28.2900 + * maximum fraction digit count is larger than
28.2901 + * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
28.2902 + * and this method throws an <code>InvalidObjectException</code>.
28.2903 + * <li>
28.2904 + * If <code>serialVersionOnStream</code> is less than 4, initialize
28.2905 + * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
28.2906 + * RoundingMode.HALF_EVEN}. This field is new with version 4.
28.2907 + * <li>
28.2908 + * If <code>serialVersionOnStream</code> is less than 3, then call
28.2909 + * the setters for the minimum and maximum integer and fraction digits with
28.2910 + * the values of the corresponding superclass getters to initialize the
28.2911 + * fields in this class. The fields in this class are new with version 3.
28.2912 + * <li>
28.2913 + * If <code>serialVersionOnStream</code> is less than 1, indicating that
28.2914 + * the stream was written by JDK 1.1, initialize
28.2915 + * <code>useExponentialNotation</code>
28.2916 + * to false, since it was not present in JDK 1.1.
28.2917 + * <li>
28.2918 + * Set <code>serialVersionOnStream</code> to the maximum allowed value so
28.2919 + * that default serialization will work properly if this object is streamed
28.2920 + * out again.
28.2921 + * </ol>
28.2922 + *
28.2923 + * <p>Stream versions older than 2 will not have the affix pattern variables
28.2924 + * <code>posPrefixPattern</code> etc. As a result, they will be initialized
28.2925 + * to <code>null</code>, which means the affix strings will be taken as
28.2926 + * literal values. This is exactly what we want, since that corresponds to
28.2927 + * the pre-version-2 behavior.
28.2928 + */
28.2929 + private void readObject(ObjectInputStream stream)
28.2930 + throws IOException, ClassNotFoundException
28.2931 + {
28.2932 + stream.defaultReadObject();
28.2933 + digitList = new DigitList();
28.2934 +
28.2935 + if (serialVersionOnStream < 4) {
28.2936 + setRoundingMode(RoundingMode.HALF_EVEN);
28.2937 + }
28.2938 + // We only need to check the maximum counts because NumberFormat
28.2939 + // .readObject has already ensured that the maximum is greater than the
28.2940 + // minimum count.
28.2941 + if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
28.2942 + super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
28.2943 + throw new InvalidObjectException("Digit count out of range");
28.2944 + }
28.2945 + if (serialVersionOnStream < 3) {
28.2946 + setMaximumIntegerDigits(super.getMaximumIntegerDigits());
28.2947 + setMinimumIntegerDigits(super.getMinimumIntegerDigits());
28.2948 + setMaximumFractionDigits(super.getMaximumFractionDigits());
28.2949 + setMinimumFractionDigits(super.getMinimumFractionDigits());
28.2950 + }
28.2951 + if (serialVersionOnStream < 1) {
28.2952 + // Didn't have exponential fields
28.2953 + useExponentialNotation = false;
28.2954 + }
28.2955 + serialVersionOnStream = currentSerialVersion;
28.2956 + }
28.2957 +
28.2958 + //----------------------------------------------------------------------
28.2959 + // INSTANCE VARIABLES
28.2960 + //----------------------------------------------------------------------
28.2961 +
28.2962 + private transient DigitList digitList = new DigitList();
28.2963 +
28.2964 + /**
28.2965 + * The symbol used as a prefix when formatting positive numbers, e.g. "+".
28.2966 + *
28.2967 + * @serial
28.2968 + * @see #getPositivePrefix
28.2969 + */
28.2970 + private String positivePrefix = "";
28.2971 +
28.2972 + /**
28.2973 + * The symbol used as a suffix when formatting positive numbers.
28.2974 + * This is often an empty string.
28.2975 + *
28.2976 + * @serial
28.2977 + * @see #getPositiveSuffix
28.2978 + */
28.2979 + private String positiveSuffix = "";
28.2980 +
28.2981 + /**
28.2982 + * The symbol used as a prefix when formatting negative numbers, e.g. "-".
28.2983 + *
28.2984 + * @serial
28.2985 + * @see #getNegativePrefix
28.2986 + */
28.2987 + private String negativePrefix = "-";
28.2988 +
28.2989 + /**
28.2990 + * The symbol used as a suffix when formatting negative numbers.
28.2991 + * This is often an empty string.
28.2992 + *
28.2993 + * @serial
28.2994 + * @see #getNegativeSuffix
28.2995 + */
28.2996 + private String negativeSuffix = "";
28.2997 +
28.2998 + /**
28.2999 + * The prefix pattern for non-negative numbers. This variable corresponds
28.3000 + * to <code>positivePrefix</code>.
28.3001 + *
28.3002 + * <p>This pattern is expanded by the method <code>expandAffix()</code> to
28.3003 + * <code>positivePrefix</code> to update the latter to reflect changes in
28.3004 + * <code>symbols</code>. If this variable is <code>null</code> then
28.3005 + * <code>positivePrefix</code> is taken as a literal value that does not
28.3006 + * change when <code>symbols</code> changes. This variable is always
28.3007 + * <code>null</code> for <code>DecimalFormat</code> objects older than
28.3008 + * stream version 2 restored from stream.
28.3009 + *
28.3010 + * @serial
28.3011 + * @since 1.3
28.3012 + */
28.3013 + private String posPrefixPattern;
28.3014 +
28.3015 + /**
28.3016 + * The suffix pattern for non-negative numbers. This variable corresponds
28.3017 + * to <code>positiveSuffix</code>. This variable is analogous to
28.3018 + * <code>posPrefixPattern</code>; see that variable for further
28.3019 + * documentation.
28.3020 + *
28.3021 + * @serial
28.3022 + * @since 1.3
28.3023 + */
28.3024 + private String posSuffixPattern;
28.3025 +
28.3026 + /**
28.3027 + * The prefix pattern for negative numbers. This variable corresponds
28.3028 + * to <code>negativePrefix</code>. This variable is analogous to
28.3029 + * <code>posPrefixPattern</code>; see that variable for further
28.3030 + * documentation.
28.3031 + *
28.3032 + * @serial
28.3033 + * @since 1.3
28.3034 + */
28.3035 + private String negPrefixPattern;
28.3036 +
28.3037 + /**
28.3038 + * The suffix pattern for negative numbers. This variable corresponds
28.3039 + * to <code>negativeSuffix</code>. This variable is analogous to
28.3040 + * <code>posPrefixPattern</code>; see that variable for further
28.3041 + * documentation.
28.3042 + *
28.3043 + * @serial
28.3044 + * @since 1.3
28.3045 + */
28.3046 + private String negSuffixPattern;
28.3047 +
28.3048 + /**
28.3049 + * The multiplier for use in percent, per mille, etc.
28.3050 + *
28.3051 + * @serial
28.3052 + * @see #getMultiplier
28.3053 + */
28.3054 + private int multiplier = 1;
28.3055 +
28.3056 + /**
28.3057 + * The number of digits between grouping separators in the integer
28.3058 + * portion of a number. Must be greater than 0 if
28.3059 + * <code>NumberFormat.groupingUsed</code> is true.
28.3060 + *
28.3061 + * @serial
28.3062 + * @see #getGroupingSize
28.3063 + * @see java.text.NumberFormat#isGroupingUsed
28.3064 + */
28.3065 + private byte groupingSize = 3; // invariant, > 0 if useThousands
28.3066 +
28.3067 + /**
28.3068 + * If true, forces the decimal separator to always appear in a formatted
28.3069 + * number, even if the fractional part of the number is zero.
28.3070 + *
28.3071 + * @serial
28.3072 + * @see #isDecimalSeparatorAlwaysShown
28.3073 + */
28.3074 + private boolean decimalSeparatorAlwaysShown = false;
28.3075 +
28.3076 + /**
28.3077 + * If true, parse returns BigDecimal wherever possible.
28.3078 + *
28.3079 + * @serial
28.3080 + * @see #isParseBigDecimal
28.3081 + * @since 1.5
28.3082 + */
28.3083 + private boolean parseBigDecimal = false;
28.3084 +
28.3085 +
28.3086 + /**
28.3087 + * True if this object represents a currency format. This determines
28.3088 + * whether the monetary decimal separator is used instead of the normal one.
28.3089 + */
28.3090 + private transient boolean isCurrencyFormat = false;
28.3091 +
28.3092 + /**
28.3093 + * The <code>DecimalFormatSymbols</code> object used by this format.
28.3094 + * It contains the symbols used to format numbers, e.g. the grouping separator,
28.3095 + * decimal separator, and so on.
28.3096 + *
28.3097 + * @serial
28.3098 + * @see #setDecimalFormatSymbols
28.3099 + * @see java.text.DecimalFormatSymbols
28.3100 + */
28.3101 + private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
28.3102 +
28.3103 + /**
28.3104 + * True to force the use of exponential (i.e. scientific) notation when formatting
28.3105 + * numbers.
28.3106 + *
28.3107 + * @serial
28.3108 + * @since 1.2
28.3109 + */
28.3110 + private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2
28.3111 +
28.3112 + /**
28.3113 + * FieldPositions describing the positive prefix String. This is
28.3114 + * lazily created. Use <code>getPositivePrefixFieldPositions</code>
28.3115 + * when needed.
28.3116 + */
28.3117 + private transient FieldPosition[] positivePrefixFieldPositions;
28.3118 +
28.3119 + /**
28.3120 + * FieldPositions describing the positive suffix String. This is
28.3121 + * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
28.3122 + * when needed.
28.3123 + */
28.3124 + private transient FieldPosition[] positiveSuffixFieldPositions;
28.3125 +
28.3126 + /**
28.3127 + * FieldPositions describing the negative prefix String. This is
28.3128 + * lazily created. Use <code>getNegativePrefixFieldPositions</code>
28.3129 + * when needed.
28.3130 + */
28.3131 + private transient FieldPosition[] negativePrefixFieldPositions;
28.3132 +
28.3133 + /**
28.3134 + * FieldPositions describing the negative suffix String. This is
28.3135 + * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
28.3136 + * when needed.
28.3137 + */
28.3138 + private transient FieldPosition[] negativeSuffixFieldPositions;
28.3139 +
28.3140 + /**
28.3141 + * The minimum number of digits used to display the exponent when a number is
28.3142 + * formatted in exponential notation. This field is ignored if
28.3143 + * <code>useExponentialNotation</code> is not true.
28.3144 + *
28.3145 + * @serial
28.3146 + * @since 1.2
28.3147 + */
28.3148 + private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2
28.3149 +
28.3150 + /**
28.3151 + * The maximum number of digits allowed in the integer portion of a
28.3152 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
28.3153 + * <code>maximumIntegerDigits</code> must be greater than or equal to
28.3154 + * <code>minimumIntegerDigits</code>.
28.3155 + *
28.3156 + * @serial
28.3157 + * @see #getMaximumIntegerDigits
28.3158 + * @since 1.5
28.3159 + */
28.3160 + private int maximumIntegerDigits = super.getMaximumIntegerDigits();
28.3161 +
28.3162 + /**
28.3163 + * The minimum number of digits allowed in the integer portion of a
28.3164 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
28.3165 + * <code>minimumIntegerDigits</code> must be less than or equal to
28.3166 + * <code>maximumIntegerDigits</code>.
28.3167 + *
28.3168 + * @serial
28.3169 + * @see #getMinimumIntegerDigits
28.3170 + * @since 1.5
28.3171 + */
28.3172 + private int minimumIntegerDigits = super.getMinimumIntegerDigits();
28.3173 +
28.3174 + /**
28.3175 + * The maximum number of digits allowed in the fractional portion of a
28.3176 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
28.3177 + * <code>maximumFractionDigits</code> must be greater than or equal to
28.3178 + * <code>minimumFractionDigits</code>.
28.3179 + *
28.3180 + * @serial
28.3181 + * @see #getMaximumFractionDigits
28.3182 + * @since 1.5
28.3183 + */
28.3184 + private int maximumFractionDigits = super.getMaximumFractionDigits();
28.3185 +
28.3186 + /**
28.3187 + * The minimum number of digits allowed in the fractional portion of a
28.3188 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
28.3189 + * <code>minimumFractionDigits</code> must be less than or equal to
28.3190 + * <code>maximumFractionDigits</code>.
28.3191 + *
28.3192 + * @serial
28.3193 + * @see #getMinimumFractionDigits
28.3194 + * @since 1.5
28.3195 + */
28.3196 + private int minimumFractionDigits = super.getMinimumFractionDigits();
28.3197 +
28.3198 + /**
28.3199 + * The {@link java.math.RoundingMode} used in this DecimalFormat.
28.3200 + *
28.3201 + * @serial
28.3202 + * @since 1.6
28.3203 + */
28.3204 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
28.3205 +
28.3206 + //----------------------------------------------------------------------
28.3207 +
28.3208 + static final int currentSerialVersion = 4;
28.3209 +
28.3210 + /**
28.3211 + * The internal serial version which says which version was written.
28.3212 + * Possible values are:
28.3213 + * <ul>
28.3214 + * <li><b>0</b> (default): versions before the Java 2 platform v1.2
28.3215 + * <li><b>1</b>: version for 1.2, which includes the two new fields
28.3216 + * <code>useExponentialNotation</code> and
28.3217 + * <code>minExponentDigits</code>.
28.3218 + * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
28.3219 + * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
28.3220 + * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
28.3221 + * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
28.3222 + * <code>maximumIntegerDigits</code>,
28.3223 + * <code>minimumIntegerDigits</code>,
28.3224 + * <code>maximumFractionDigits</code>,
28.3225 + * <code>minimumFractionDigits</code>, and
28.3226 + * <code>parseBigDecimal</code>.
28.3227 + * <li><b>4</b>: version for 1.6 and later, which adds one new field:
28.3228 + * <code>roundingMode</code>.
28.3229 + * </ul>
28.3230 + * @since 1.2
28.3231 + * @serial
28.3232 + */
28.3233 + private int serialVersionOnStream = currentSerialVersion;
28.3234 +
28.3235 + //----------------------------------------------------------------------
28.3236 + // CONSTANTS
28.3237 + //----------------------------------------------------------------------
28.3238 +
28.3239 + // Constants for characters used in programmatic (unlocalized) patterns.
28.3240 + private static final char PATTERN_ZERO_DIGIT = '0';
28.3241 + private static final char PATTERN_GROUPING_SEPARATOR = ',';
28.3242 + private static final char PATTERN_DECIMAL_SEPARATOR = '.';
28.3243 + private static final char PATTERN_PER_MILLE = '\u2030';
28.3244 + private static final char PATTERN_PERCENT = '%';
28.3245 + private static final char PATTERN_DIGIT = '#';
28.3246 + private static final char PATTERN_SEPARATOR = ';';
28.3247 + private static final String PATTERN_EXPONENT = "E";
28.3248 + private static final char PATTERN_MINUS = '-';
28.3249 +
28.3250 + /**
28.3251 + * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
28.3252 + * is used in patterns and substituted with either the currency symbol,
28.3253 + * or if it is doubled, with the international currency symbol. If the
28.3254 + * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
28.3255 + * replaced with the monetary decimal separator.
28.3256 + *
28.3257 + * The CURRENCY_SIGN is not localized.
28.3258 + */
28.3259 + private static final char CURRENCY_SIGN = '\u00A4';
28.3260 +
28.3261 + private static final char QUOTE = '\'';
28.3262 +
28.3263 + private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
28.3264 +
28.3265 + // Upper limit on integer and fraction digits for a Java double
28.3266 + static final int DOUBLE_INTEGER_DIGITS = 309;
28.3267 + static final int DOUBLE_FRACTION_DIGITS = 340;
28.3268 +
28.3269 + // Upper limit on integer and fraction digits for BigDecimal and BigInteger
28.3270 + static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE;
28.3271 + static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
28.3272 +
28.3273 + // Proclaim JDK 1.1 serial compatibility.
28.3274 + static final long serialVersionUID = 864413376551465018L;
28.3275 +
28.3276 + /**
28.3277 + * Cache to hold the NumberPattern of a Locale.
28.3278 + */
28.3279 + private static final ConcurrentMap<Locale, String> cachedLocaleData
28.3280 + = new ConcurrentHashMap<Locale, String>(3);
28.3281 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormatSymbols.java Thu Oct 03 15:40:35 2013 +0200
29.3 @@ -0,0 +1,837 @@
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, 1997 - All Rights Reserved
29.31 + * (C) Copyright IBM Corp. 1996 - 1998 - 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.ObjectInputStream;
29.46 +import java.io.Serializable;
29.47 +import java.text.spi.DecimalFormatSymbolsProvider;
29.48 +import java.util.Currency;
29.49 +import java.util.Locale;
29.50 +import java.util.ResourceBundle;
29.51 +import java.util.concurrent.ConcurrentHashMap;
29.52 +
29.53 +import sun.util.LocaleServiceProviderPool;
29.54 +import sun.util.resources.LocaleData;
29.55 +
29.56 +/**
29.57 + * This class represents the set of symbols (such as the decimal separator,
29.58 + * the grouping separator, and so on) needed by <code>DecimalFormat</code>
29.59 + * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
29.60 + * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
29.61 + * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
29.62 + * your <code>DecimalFormat</code> and modify it.
29.63 + *
29.64 + * @see java.util.Locale
29.65 + * @see DecimalFormat
29.66 + * @author Mark Davis
29.67 + * @author Alan Liu
29.68 + */
29.69 +
29.70 +public class DecimalFormatSymbols implements Cloneable, Serializable {
29.71 +
29.72 + /**
29.73 + * Create a DecimalFormatSymbols object for the default locale.
29.74 + * This constructor can only construct instances for the locales
29.75 + * supported by the Java runtime environment, not for those
29.76 + * supported by installed
29.77 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
29.78 + * implementations. For full locale coverage, use the
29.79 + * {@link #getInstance(Locale) getInstance} method.
29.80 + */
29.81 + public DecimalFormatSymbols() {
29.82 + initialize( Locale.getDefault(Locale.Category.FORMAT) );
29.83 + }
29.84 +
29.85 + /**
29.86 + * Create a DecimalFormatSymbols object for the given locale.
29.87 + * This constructor can only construct instances for the locales
29.88 + * supported by the Java runtime environment, not for those
29.89 + * supported by installed
29.90 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
29.91 + * implementations. For full locale coverage, use the
29.92 + * {@link #getInstance(Locale) getInstance} method.
29.93 + *
29.94 + * @exception NullPointerException if <code>locale</code> is null
29.95 + */
29.96 + public DecimalFormatSymbols( Locale locale ) {
29.97 + initialize( locale );
29.98 + }
29.99 +
29.100 + /**
29.101 + * Returns an array of all locales for which the
29.102 + * <code>getInstance</code> methods of this class can return
29.103 + * localized instances.
29.104 + * The returned array represents the union of locales supported by the Java
29.105 + * runtime and by installed
29.106 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
29.107 + * implementations. It must contain at least a <code>Locale</code>
29.108 + * instance equal to {@link java.util.Locale#US Locale.US}.
29.109 + *
29.110 + * @return An array of locales for which localized
29.111 + * <code>DecimalFormatSymbols</code> instances are available.
29.112 + * @since 1.6
29.113 + */
29.114 + public static Locale[] getAvailableLocales() {
29.115 + LocaleServiceProviderPool pool =
29.116 + LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
29.117 + return pool.getAvailableLocales();
29.118 + }
29.119 +
29.120 + /**
29.121 + * Gets the <code>DecimalFormatSymbols</code> instance for the default
29.122 + * locale. This method provides access to <code>DecimalFormatSymbols</code>
29.123 + * instances for locales supported by the Java runtime itself as well
29.124 + * as for those supported by installed
29.125 + * {@link java.text.spi.DecimalFormatSymbolsProvider
29.126 + * DecimalFormatSymbolsProvider} implementations.
29.127 + * @return a <code>DecimalFormatSymbols</code> instance.
29.128 + * @since 1.6
29.129 + */
29.130 + public static final DecimalFormatSymbols getInstance() {
29.131 + return getInstance(Locale.getDefault(Locale.Category.FORMAT));
29.132 + }
29.133 +
29.134 + /**
29.135 + * Gets the <code>DecimalFormatSymbols</code> instance for the specified
29.136 + * locale. This method provides access to <code>DecimalFormatSymbols</code>
29.137 + * instances for locales supported by the Java runtime itself as well
29.138 + * as for those supported by installed
29.139 + * {@link java.text.spi.DecimalFormatSymbolsProvider
29.140 + * DecimalFormatSymbolsProvider} implementations.
29.141 + * @param locale the desired locale.
29.142 + * @return a <code>DecimalFormatSymbols</code> instance.
29.143 + * @exception NullPointerException if <code>locale</code> is null
29.144 + * @since 1.6
29.145 + */
29.146 + public static final DecimalFormatSymbols getInstance(Locale locale) {
29.147 +
29.148 + // Check whether a provider can provide an implementation that's closer
29.149 + // to the requested locale than what the Java runtime itself can provide.
29.150 + LocaleServiceProviderPool pool =
29.151 + LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
29.152 + if (pool.hasProviders()) {
29.153 + DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
29.154 + DecimalFormatSymbolsGetter.INSTANCE, locale);
29.155 + if (providersInstance != null) {
29.156 + return providersInstance;
29.157 + }
29.158 + }
29.159 +
29.160 + return new DecimalFormatSymbols(locale);
29.161 + }
29.162 +
29.163 + /**
29.164 + * Gets the character used for zero. Different for Arabic, etc.
29.165 + */
29.166 + public char getZeroDigit() {
29.167 + return zeroDigit;
29.168 + }
29.169 +
29.170 + /**
29.171 + * Sets the character used for zero. Different for Arabic, etc.
29.172 + */
29.173 + public void setZeroDigit(char zeroDigit) {
29.174 + this.zeroDigit = zeroDigit;
29.175 + }
29.176 +
29.177 + /**
29.178 + * Gets the character used for thousands separator. Different for French, etc.
29.179 + */
29.180 + public char getGroupingSeparator() {
29.181 + return groupingSeparator;
29.182 + }
29.183 +
29.184 + /**
29.185 + * Sets the character used for thousands separator. Different for French, etc.
29.186 + */
29.187 + public void setGroupingSeparator(char groupingSeparator) {
29.188 + this.groupingSeparator = groupingSeparator;
29.189 + }
29.190 +
29.191 + /**
29.192 + * Gets the character used for decimal sign. Different for French, etc.
29.193 + */
29.194 + public char getDecimalSeparator() {
29.195 + return decimalSeparator;
29.196 + }
29.197 +
29.198 + /**
29.199 + * Sets the character used for decimal sign. Different for French, etc.
29.200 + */
29.201 + public void setDecimalSeparator(char decimalSeparator) {
29.202 + this.decimalSeparator = decimalSeparator;
29.203 + }
29.204 +
29.205 + /**
29.206 + * Gets the character used for per mille sign. Different for Arabic, etc.
29.207 + */
29.208 + public char getPerMill() {
29.209 + return perMill;
29.210 + }
29.211 +
29.212 + /**
29.213 + * Sets the character used for per mille sign. Different for Arabic, etc.
29.214 + */
29.215 + public void setPerMill(char perMill) {
29.216 + this.perMill = perMill;
29.217 + }
29.218 +
29.219 + /**
29.220 + * Gets the character used for percent sign. Different for Arabic, etc.
29.221 + */
29.222 + public char getPercent() {
29.223 + return percent;
29.224 + }
29.225 +
29.226 + /**
29.227 + * Sets the character used for percent sign. Different for Arabic, etc.
29.228 + */
29.229 + public void setPercent(char percent) {
29.230 + this.percent = percent;
29.231 + }
29.232 +
29.233 + /**
29.234 + * Gets the character used for a digit in a pattern.
29.235 + */
29.236 + public char getDigit() {
29.237 + return digit;
29.238 + }
29.239 +
29.240 + /**
29.241 + * Sets the character used for a digit in a pattern.
29.242 + */
29.243 + public void setDigit(char digit) {
29.244 + this.digit = digit;
29.245 + }
29.246 +
29.247 + /**
29.248 + * Gets the character used to separate positive and negative subpatterns
29.249 + * in a pattern.
29.250 + */
29.251 + public char getPatternSeparator() {
29.252 + return patternSeparator;
29.253 + }
29.254 +
29.255 + /**
29.256 + * Sets the character used to separate positive and negative subpatterns
29.257 + * in a pattern.
29.258 + */
29.259 + public void setPatternSeparator(char patternSeparator) {
29.260 + this.patternSeparator = patternSeparator;
29.261 + }
29.262 +
29.263 + /**
29.264 + * Gets the string used to represent infinity. Almost always left
29.265 + * unchanged.
29.266 + */
29.267 + public String getInfinity() {
29.268 + return infinity;
29.269 + }
29.270 +
29.271 + /**
29.272 + * Sets the string used to represent infinity. Almost always left
29.273 + * unchanged.
29.274 + */
29.275 + public void setInfinity(String infinity) {
29.276 + this.infinity = infinity;
29.277 + }
29.278 +
29.279 + /**
29.280 + * Gets the string used to represent "not a number". Almost always left
29.281 + * unchanged.
29.282 + */
29.283 + public String getNaN() {
29.284 + return NaN;
29.285 + }
29.286 +
29.287 + /**
29.288 + * Sets the string used to represent "not a number". Almost always left
29.289 + * unchanged.
29.290 + */
29.291 + public void setNaN(String NaN) {
29.292 + this.NaN = NaN;
29.293 + }
29.294 +
29.295 + /**
29.296 + * Gets the character used to represent minus sign. If no explicit
29.297 + * negative format is specified, one is formed by prefixing
29.298 + * minusSign to the positive format.
29.299 + */
29.300 + public char getMinusSign() {
29.301 + return minusSign;
29.302 + }
29.303 +
29.304 + /**
29.305 + * Sets the character used to represent minus sign. If no explicit
29.306 + * negative format is specified, one is formed by prefixing
29.307 + * minusSign to the positive format.
29.308 + */
29.309 + public void setMinusSign(char minusSign) {
29.310 + this.minusSign = minusSign;
29.311 + }
29.312 +
29.313 + /**
29.314 + * Returns the currency symbol for the currency of these
29.315 + * DecimalFormatSymbols in their locale.
29.316 + * @since 1.2
29.317 + */
29.318 + public String getCurrencySymbol()
29.319 + {
29.320 + return currencySymbol;
29.321 + }
29.322 +
29.323 + /**
29.324 + * Sets the currency symbol for the currency of these
29.325 + * DecimalFormatSymbols in their locale.
29.326 + * @since 1.2
29.327 + */
29.328 + public void setCurrencySymbol(String currency)
29.329 + {
29.330 + currencySymbol = currency;
29.331 + }
29.332 +
29.333 + /**
29.334 + * Returns the ISO 4217 currency code of the currency of these
29.335 + * DecimalFormatSymbols.
29.336 + * @since 1.2
29.337 + */
29.338 + public String getInternationalCurrencySymbol()
29.339 + {
29.340 + return intlCurrencySymbol;
29.341 + }
29.342 +
29.343 + /**
29.344 + * Sets the ISO 4217 currency code of the currency of these
29.345 + * DecimalFormatSymbols.
29.346 + * If the currency code is valid (as defined by
29.347 + * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
29.348 + * this also sets the currency attribute to the corresponding Currency
29.349 + * instance and the currency symbol attribute to the currency's symbol
29.350 + * in the DecimalFormatSymbols' locale. If the currency code is not valid,
29.351 + * then the currency attribute is set to null and the currency symbol
29.352 + * attribute is not modified.
29.353 + *
29.354 + * @see #setCurrency
29.355 + * @see #setCurrencySymbol
29.356 + * @since 1.2
29.357 + */
29.358 + public void setInternationalCurrencySymbol(String currencyCode)
29.359 + {
29.360 + intlCurrencySymbol = currencyCode;
29.361 + currency = null;
29.362 + if (currencyCode != null) {
29.363 + try {
29.364 + currency = Currency.getInstance(currencyCode);
29.365 + currencySymbol = currency.getSymbol();
29.366 + } catch (IllegalArgumentException e) {
29.367 + }
29.368 + }
29.369 + }
29.370 +
29.371 + /**
29.372 + * Gets the currency of these DecimalFormatSymbols. May be null if the
29.373 + * currency symbol attribute was previously set to a value that's not
29.374 + * a valid ISO 4217 currency code.
29.375 + *
29.376 + * @return the currency used, or null
29.377 + * @since 1.4
29.378 + */
29.379 + public Currency getCurrency() {
29.380 + return currency;
29.381 + }
29.382 +
29.383 + /**
29.384 + * Sets the currency of these DecimalFormatSymbols.
29.385 + * This also sets the currency symbol attribute to the currency's symbol
29.386 + * in the DecimalFormatSymbols' locale, and the international currency
29.387 + * symbol attribute to the currency's ISO 4217 currency code.
29.388 + *
29.389 + * @param currency the new currency to be used
29.390 + * @exception NullPointerException if <code>currency</code> is null
29.391 + * @since 1.4
29.392 + * @see #setCurrencySymbol
29.393 + * @see #setInternationalCurrencySymbol
29.394 + */
29.395 + public void setCurrency(Currency currency) {
29.396 + if (currency == null) {
29.397 + throw new NullPointerException();
29.398 + }
29.399 + this.currency = currency;
29.400 + intlCurrencySymbol = currency.getCurrencyCode();
29.401 + currencySymbol = currency.getSymbol(locale);
29.402 + }
29.403 +
29.404 +
29.405 + /**
29.406 + * Returns the monetary decimal separator.
29.407 + * @since 1.2
29.408 + */
29.409 + public char getMonetaryDecimalSeparator()
29.410 + {
29.411 + return monetarySeparator;
29.412 + }
29.413 +
29.414 + /**
29.415 + * Sets the monetary decimal separator.
29.416 + * @since 1.2
29.417 + */
29.418 + public void setMonetaryDecimalSeparator(char sep)
29.419 + {
29.420 + monetarySeparator = sep;
29.421 + }
29.422 +
29.423 + //------------------------------------------------------------
29.424 + // BEGIN Package Private methods ... to be made public later
29.425 + //------------------------------------------------------------
29.426 +
29.427 + /**
29.428 + * Returns the character used to separate the mantissa from the exponent.
29.429 + */
29.430 + char getExponentialSymbol()
29.431 + {
29.432 + return exponential;
29.433 + }
29.434 + /**
29.435 + * Returns the string used to separate the mantissa from the exponent.
29.436 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
29.437 + *
29.438 + * @return the exponent separator string
29.439 + * @see #setExponentSeparator(java.lang.String)
29.440 + * @since 1.6
29.441 + */
29.442 + public String getExponentSeparator()
29.443 + {
29.444 + return exponentialSeparator;
29.445 + }
29.446 +
29.447 + /**
29.448 + * Sets the character used to separate the mantissa from the exponent.
29.449 + */
29.450 + void setExponentialSymbol(char exp)
29.451 + {
29.452 + exponential = exp;
29.453 + }
29.454 +
29.455 + /**
29.456 + * Sets the string used to separate the mantissa from the exponent.
29.457 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
29.458 + *
29.459 + * @param exp the exponent separator string
29.460 + * @exception NullPointerException if <code>exp</code> is null
29.461 + * @see #getExponentSeparator()
29.462 + * @since 1.6
29.463 + */
29.464 + public void setExponentSeparator(String exp)
29.465 + {
29.466 + if (exp == null) {
29.467 + throw new NullPointerException();
29.468 + }
29.469 + exponentialSeparator = exp;
29.470 + }
29.471 +
29.472 +
29.473 + //------------------------------------------------------------
29.474 + // END Package Private methods ... to be made public later
29.475 + //------------------------------------------------------------
29.476 +
29.477 + /**
29.478 + * Standard override.
29.479 + */
29.480 + public Object clone() {
29.481 + try {
29.482 + return (DecimalFormatSymbols)super.clone();
29.483 + // other fields are bit-copied
29.484 + } catch (CloneNotSupportedException e) {
29.485 + throw new InternalError();
29.486 + }
29.487 + }
29.488 +
29.489 + /**
29.490 + * Override equals.
29.491 + */
29.492 + public boolean equals(Object obj) {
29.493 + if (obj == null) return false;
29.494 + if (this == obj) return true;
29.495 + if (getClass() != obj.getClass()) return false;
29.496 + DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
29.497 + return (zeroDigit == other.zeroDigit &&
29.498 + groupingSeparator == other.groupingSeparator &&
29.499 + decimalSeparator == other.decimalSeparator &&
29.500 + percent == other.percent &&
29.501 + perMill == other.perMill &&
29.502 + digit == other.digit &&
29.503 + minusSign == other.minusSign &&
29.504 + patternSeparator == other.patternSeparator &&
29.505 + infinity.equals(other.infinity) &&
29.506 + NaN.equals(other.NaN) &&
29.507 + currencySymbol.equals(other.currencySymbol) &&
29.508 + intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
29.509 + currency == other.currency &&
29.510 + monetarySeparator == other.monetarySeparator &&
29.511 + exponentialSeparator.equals(other.exponentialSeparator) &&
29.512 + locale.equals(other.locale));
29.513 + }
29.514 +
29.515 + /**
29.516 + * Override hashCode.
29.517 + */
29.518 + public int hashCode() {
29.519 + int result = zeroDigit;
29.520 + result = result * 37 + groupingSeparator;
29.521 + result = result * 37 + decimalSeparator;
29.522 + return result;
29.523 + }
29.524 +
29.525 + /**
29.526 + * Initializes the symbols from the FormatData resource bundle.
29.527 + */
29.528 + private void initialize( Locale locale ) {
29.529 + this.locale = locale;
29.530 +
29.531 + // get resource bundle data - try the cache first
29.532 + boolean needCacheUpdate = false;
29.533 + Object[] data = cachedLocaleData.get(locale);
29.534 + if (data == null) { /* cache miss */
29.535 + // When numbering system is thai (Locale's extension contains u-nu-thai),
29.536 + // we read the data from th_TH_TH.
29.537 + Locale lookupLocale = locale;
29.538 + String numberType = locale.getUnicodeLocaleType("nu");
29.539 + if (numberType != null && numberType.equals("thai")) {
29.540 + lookupLocale = new Locale("th", "TH", "TH");
29.541 + }
29.542 + data = new Object[3];
29.543 + ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);
29.544 + data[0] = rb.getStringArray("NumberElements");
29.545 + needCacheUpdate = true;
29.546 + }
29.547 +
29.548 + String[] numberElements = (String[]) data[0];
29.549 +
29.550 + decimalSeparator = numberElements[0].charAt(0);
29.551 + groupingSeparator = numberElements[1].charAt(0);
29.552 + patternSeparator = numberElements[2].charAt(0);
29.553 + percent = numberElements[3].charAt(0);
29.554 + zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
29.555 + digit = numberElements[5].charAt(0);
29.556 + minusSign = numberElements[6].charAt(0);
29.557 + exponential = numberElements[7].charAt(0);
29.558 + exponentialSeparator = numberElements[7]; //string representation new since 1.6
29.559 + perMill = numberElements[8].charAt(0);
29.560 + infinity = numberElements[9];
29.561 + NaN = numberElements[10];
29.562 +
29.563 + // Try to obtain the currency used in the locale's country.
29.564 + // Check for empty country string separately because it's a valid
29.565 + // country ID for Locale (and used for the C locale), but not a valid
29.566 + // ISO 3166 country code, and exceptions are expensive.
29.567 + if (!"".equals(locale.getCountry())) {
29.568 + try {
29.569 + currency = Currency.getInstance(locale);
29.570 + } catch (IllegalArgumentException e) {
29.571 + // use default values below for compatibility
29.572 + }
29.573 + }
29.574 + if (currency != null) {
29.575 + intlCurrencySymbol = currency.getCurrencyCode();
29.576 + if (data[1] != null && data[1] == intlCurrencySymbol) {
29.577 + currencySymbol = (String) data[2];
29.578 + } else {
29.579 + currencySymbol = currency.getSymbol(locale);
29.580 + data[1] = intlCurrencySymbol;
29.581 + data[2] = currencySymbol;
29.582 + needCacheUpdate = true;
29.583 + }
29.584 + } else {
29.585 + // default values
29.586 + intlCurrencySymbol = "XXX";
29.587 + try {
29.588 + currency = Currency.getInstance(intlCurrencySymbol);
29.589 + } catch (IllegalArgumentException e) {
29.590 + }
29.591 + currencySymbol = "\u00A4";
29.592 + }
29.593 + // Currently the monetary decimal separator is the same as the
29.594 + // standard decimal separator for all locales that we support.
29.595 + // If that changes, add a new entry to NumberElements.
29.596 + monetarySeparator = decimalSeparator;
29.597 +
29.598 + if (needCacheUpdate) {
29.599 + cachedLocaleData.putIfAbsent(locale, data);
29.600 + }
29.601 + }
29.602 +
29.603 + /**
29.604 + * Reads the default serializable fields, provides default values for objects
29.605 + * in older serial versions, and initializes non-serializable fields.
29.606 + * If <code>serialVersionOnStream</code>
29.607 + * is less than 1, initializes <code>monetarySeparator</code> to be
29.608 + * the same as <code>decimalSeparator</code> and <code>exponential</code>
29.609 + * to be 'E'.
29.610 + * If <code>serialVersionOnStream</code> is less than 2,
29.611 + * initializes <code>locale</code>to the root locale, and initializes
29.612 + * If <code>serialVersionOnStream</code> is less than 3, it initializes
29.613 + * <code>exponentialSeparator</code> using <code>exponential</code>.
29.614 + * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
29.615 + * default serialization will work properly if this object is streamed out again.
29.616 + * Initializes the currency from the intlCurrencySymbol field.
29.617 + *
29.618 + * @since JDK 1.1.6
29.619 + */
29.620 + private void readObject(ObjectInputStream stream)
29.621 + throws IOException, ClassNotFoundException {
29.622 + stream.defaultReadObject();
29.623 + if (serialVersionOnStream < 1) {
29.624 + // Didn't have monetarySeparator or exponential field;
29.625 + // use defaults.
29.626 + monetarySeparator = decimalSeparator;
29.627 + exponential = 'E';
29.628 + }
29.629 + if (serialVersionOnStream < 2) {
29.630 + // didn't have locale; use root locale
29.631 + locale = Locale.ROOT;
29.632 + }
29.633 + if (serialVersionOnStream < 3) {
29.634 + // didn't have exponentialSeparator. Create one using exponential
29.635 + exponentialSeparator = Character.toString(exponential);
29.636 + }
29.637 + serialVersionOnStream = currentSerialVersion;
29.638 +
29.639 + if (intlCurrencySymbol != null) {
29.640 + try {
29.641 + currency = Currency.getInstance(intlCurrencySymbol);
29.642 + } catch (IllegalArgumentException e) {
29.643 + }
29.644 + }
29.645 + }
29.646 +
29.647 + /**
29.648 + * Character used for zero.
29.649 + *
29.650 + * @serial
29.651 + * @see #getZeroDigit
29.652 + */
29.653 + private char zeroDigit;
29.654 +
29.655 + /**
29.656 + * Character used for thousands separator.
29.657 + *
29.658 + * @serial
29.659 + * @see #getGroupingSeparator
29.660 + */
29.661 + private char groupingSeparator;
29.662 +
29.663 + /**
29.664 + * Character used for decimal sign.
29.665 + *
29.666 + * @serial
29.667 + * @see #getDecimalSeparator
29.668 + */
29.669 + private char decimalSeparator;
29.670 +
29.671 + /**
29.672 + * Character used for per mille sign.
29.673 + *
29.674 + * @serial
29.675 + * @see #getPerMill
29.676 + */
29.677 + private char perMill;
29.678 +
29.679 + /**
29.680 + * Character used for percent sign.
29.681 + * @serial
29.682 + * @see #getPercent
29.683 + */
29.684 + private char percent;
29.685 +
29.686 + /**
29.687 + * Character used for a digit in a pattern.
29.688 + *
29.689 + * @serial
29.690 + * @see #getDigit
29.691 + */
29.692 + private char digit;
29.693 +
29.694 + /**
29.695 + * Character used to separate positive and negative subpatterns
29.696 + * in a pattern.
29.697 + *
29.698 + * @serial
29.699 + * @see #getPatternSeparator
29.700 + */
29.701 + private char patternSeparator;
29.702 +
29.703 + /**
29.704 + * String used to represent infinity.
29.705 + * @serial
29.706 + * @see #getInfinity
29.707 + */
29.708 + private String infinity;
29.709 +
29.710 + /**
29.711 + * String used to represent "not a number".
29.712 + * @serial
29.713 + * @see #getNaN
29.714 + */
29.715 + private String NaN;
29.716 +
29.717 + /**
29.718 + * Character used to represent minus sign.
29.719 + * @serial
29.720 + * @see #getMinusSign
29.721 + */
29.722 + private char minusSign;
29.723 +
29.724 + /**
29.725 + * String denoting the local currency, e.g. "$".
29.726 + * @serial
29.727 + * @see #getCurrencySymbol
29.728 + */
29.729 + private String currencySymbol;
29.730 +
29.731 + /**
29.732 + * ISO 4217 currency code denoting the local currency, e.g. "USD".
29.733 + * @serial
29.734 + * @see #getInternationalCurrencySymbol
29.735 + */
29.736 + private String intlCurrencySymbol;
29.737 +
29.738 + /**
29.739 + * The decimal separator used when formatting currency values.
29.740 + * @serial
29.741 + * @since JDK 1.1.6
29.742 + * @see #getMonetaryDecimalSeparator
29.743 + */
29.744 + private char monetarySeparator; // Field new in JDK 1.1.6
29.745 +
29.746 + /**
29.747 + * The character used to distinguish the exponent in a number formatted
29.748 + * in exponential notation, e.g. 'E' for a number such as "1.23E45".
29.749 + * <p>
29.750 + * Note that the public API provides no way to set this field,
29.751 + * even though it is supported by the implementation and the stream format.
29.752 + * The intent is that this will be added to the API in the future.
29.753 + *
29.754 + * @serial
29.755 + * @since JDK 1.1.6
29.756 + */
29.757 + private char exponential; // Field new in JDK 1.1.6
29.758 +
29.759 + /**
29.760 + * The string used to separate the mantissa from the exponent.
29.761 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
29.762 + * <p>
29.763 + * If both <code>exponential</code> and <code>exponentialSeparator</code>
29.764 + * exist, this <code>exponentialSeparator</code> has the precedence.
29.765 + *
29.766 + * @serial
29.767 + * @since 1.6
29.768 + */
29.769 + private String exponentialSeparator; // Field new in JDK 1.6
29.770 +
29.771 + /**
29.772 + * The locale of these currency format symbols.
29.773 + *
29.774 + * @serial
29.775 + * @since 1.4
29.776 + */
29.777 + private Locale locale;
29.778 +
29.779 + // currency; only the ISO code is serialized.
29.780 + private transient Currency currency;
29.781 +
29.782 + // Proclaim JDK 1.1 FCS compatibility
29.783 + static final long serialVersionUID = 5772796243397350300L;
29.784 +
29.785 + // The internal serial version which says which version was written
29.786 + // - 0 (default) for version up to JDK 1.1.5
29.787 + // - 1 for version from JDK 1.1.6, which includes two new fields:
29.788 + // monetarySeparator and exponential.
29.789 + // - 2 for version from J2SE 1.4, which includes locale field.
29.790 + // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
29.791 + private static final int currentSerialVersion = 3;
29.792 +
29.793 + /**
29.794 + * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
29.795 + * Possible values are:
29.796 + * <ul>
29.797 + * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
29.798 + *
29.799 + * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
29.800 + * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
29.801 + * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
29.802 + * new <code>locale</code> field.
29.803 + * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
29.804 + * new <code>exponentialSeparator</code> field.
29.805 + * </ul>
29.806 + * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
29.807 + * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
29.808 + * is always written.
29.809 + *
29.810 + * @serial
29.811 + * @since JDK 1.1.6
29.812 + */
29.813 + private int serialVersionOnStream = currentSerialVersion;
29.814 +
29.815 + /**
29.816 + * cache to hold the NumberElements and the Currency
29.817 + * of a Locale.
29.818 + */
29.819 + private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
29.820 +
29.821 + /**
29.822 + * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
29.823 + * implementation.
29.824 + */
29.825 + private static class DecimalFormatSymbolsGetter
29.826 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
29.827 + DecimalFormatSymbols> {
29.828 + private static final DecimalFormatSymbolsGetter INSTANCE =
29.829 + new DecimalFormatSymbolsGetter();
29.830 +
29.831 + public DecimalFormatSymbols getObject(
29.832 + DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
29.833 + Locale locale,
29.834 + String key,
29.835 + Object... params) {
29.836 + assert params.length == 0;
29.837 + return decimalFormatSymbolsProvider.getInstance(locale);
29.838 + }
29.839 + }
29.840 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/rt/emul/compact/src/main/java/java/text/DigitList.java Thu Oct 03 15:40:35 2013 +0200
30.3 @@ -0,0 +1,715 @@
30.4 +/*
30.5 + * Copyright (c) 1996, 2006, 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.math.BigDecimal;
30.45 +import java.math.BigInteger;
30.46 +import java.math.RoundingMode;
30.47 +
30.48 +/**
30.49 + * Digit List. Private to DecimalFormat.
30.50 + * Handles the transcoding
30.51 + * between numeric values and strings of characters. Only handles
30.52 + * non-negative numbers. The division of labor between DigitList and
30.53 + * DecimalFormat is that DigitList handles the radix 10 representation
30.54 + * issues; DecimalFormat handles the locale-specific issues such as
30.55 + * positive/negative, grouping, decimal point, currency, and so on.
30.56 + *
30.57 + * A DigitList is really a representation of a floating point value.
30.58 + * It may be an integer value; we assume that a double has sufficient
30.59 + * precision to represent all digits of a long.
30.60 + *
30.61 + * The DigitList representation consists of a string of characters,
30.62 + * which are the digits radix 10, from '0' to '9'. It also has a radix
30.63 + * 10 exponent associated with it. The value represented by a DigitList
30.64 + * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
30.65 + * derived by placing all the digits of the list to the right of the
30.66 + * decimal point, by 10^exponent.
30.67 + *
30.68 + * @see Locale
30.69 + * @see Format
30.70 + * @see NumberFormat
30.71 + * @see DecimalFormat
30.72 + * @see ChoiceFormat
30.73 + * @see MessageFormat
30.74 + * @author Mark Davis, Alan Liu
30.75 + */
30.76 +final class DigitList implements Cloneable {
30.77 + /**
30.78 + * The maximum number of significant digits in an IEEE 754 double, that
30.79 + * is, in a Java double. This must not be increased, or garbage digits
30.80 + * will be generated, and should not be decreased, or accuracy will be lost.
30.81 + */
30.82 + public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
30.83 +
30.84 + /**
30.85 + * These data members are intentionally public and can be set directly.
30.86 + *
30.87 + * The value represented is given by placing the decimal point before
30.88 + * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
30.89 + * the decimal point and the first nonzero digit are implied. If decimalAt
30.90 + * is > count, then trailing zeros between the digits[count-1] and the
30.91 + * decimal point are implied.
30.92 + *
30.93 + * Equivalently, the represented value is given by f * 10^decimalAt. Here
30.94 + * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
30.95 + * the right of the decimal.
30.96 + *
30.97 + * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
30.98 + * don't allow denormalized numbers because our exponent is effectively of
30.99 + * unlimited magnitude. The count value contains the number of significant
30.100 + * digits present in digits[].
30.101 + *
30.102 + * Zero is represented by any DigitList with count == 0 or with each digits[i]
30.103 + * for all i <= count == '0'.
30.104 + */
30.105 + public int decimalAt = 0;
30.106 + public int count = 0;
30.107 + public char[] digits = new char[MAX_COUNT];
30.108 +
30.109 + private char[] data;
30.110 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
30.111 + private boolean isNegative = false;
30.112 +
30.113 + /**
30.114 + * Return true if the represented number is zero.
30.115 + */
30.116 + boolean isZero() {
30.117 + for (int i=0; i < count; ++i) {
30.118 + if (digits[i] != '0') {
30.119 + return false;
30.120 + }
30.121 + }
30.122 + return true;
30.123 + }
30.124 +
30.125 + /**
30.126 + * Set the rounding mode
30.127 + */
30.128 + void setRoundingMode(RoundingMode r) {
30.129 + roundingMode = r;
30.130 + }
30.131 +
30.132 + /**
30.133 + * Clears out the digits.
30.134 + * Use before appending them.
30.135 + * Typically, you set a series of digits with append, then at the point
30.136 + * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
30.137 + * then go on appending digits.
30.138 + */
30.139 + public void clear () {
30.140 + decimalAt = 0;
30.141 + count = 0;
30.142 + }
30.143 +
30.144 + /**
30.145 + * Appends a digit to the list, extending the list when necessary.
30.146 + */
30.147 + public void append(char digit) {
30.148 + if (count == digits.length) {
30.149 + char[] data = new char[count + 100];
30.150 + System.arraycopy(digits, 0, data, 0, count);
30.151 + digits = data;
30.152 + }
30.153 + digits[count++] = digit;
30.154 + }
30.155 +
30.156 + /**
30.157 + * Utility routine to get the value of the digit list
30.158 + * If (count == 0) this throws a NumberFormatException, which
30.159 + * mimics Long.parseLong().
30.160 + */
30.161 + public final double getDouble() {
30.162 + if (count == 0) {
30.163 + return 0.0;
30.164 + }
30.165 +
30.166 + StringBuffer temp = getStringBuffer();
30.167 + temp.append('.');
30.168 + temp.append(digits, 0, count);
30.169 + temp.append('E');
30.170 + temp.append(decimalAt);
30.171 + return Double.parseDouble(temp.toString());
30.172 + }
30.173 +
30.174 + /**
30.175 + * Utility routine to get the value of the digit list.
30.176 + * If (count == 0) this returns 0, unlike Long.parseLong().
30.177 + */
30.178 + public final long getLong() {
30.179 + // for now, simple implementation; later, do proper IEEE native stuff
30.180 +
30.181 + if (count == 0) {
30.182 + return 0;
30.183 + }
30.184 +
30.185 + // We have to check for this, because this is the one NEGATIVE value
30.186 + // we represent. If we tried to just pass the digits off to parseLong,
30.187 + // we'd get a parse failure.
30.188 + if (isLongMIN_VALUE()) {
30.189 + return Long.MIN_VALUE;
30.190 + }
30.191 +
30.192 + StringBuffer temp = getStringBuffer();
30.193 + temp.append(digits, 0, count);
30.194 + for (int i = count; i < decimalAt; ++i) {
30.195 + temp.append('0');
30.196 + }
30.197 + return Long.parseLong(temp.toString());
30.198 + }
30.199 +
30.200 + public final BigDecimal getBigDecimal() {
30.201 + if (count == 0) {
30.202 + if (decimalAt == 0) {
30.203 + return BigDecimal.ZERO;
30.204 + } else {
30.205 + return new BigDecimal("0E" + decimalAt);
30.206 + }
30.207 + }
30.208 +
30.209 + if (decimalAt == count) {
30.210 + return new BigDecimal(digits, 0, count);
30.211 + } else {
30.212 + return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
30.213 + }
30.214 + }
30.215 +
30.216 + /**
30.217 + * Return true if the number represented by this object can fit into
30.218 + * a long.
30.219 + * @param isPositive true if this number should be regarded as positive
30.220 + * @param ignoreNegativeZero true if -0 should be regarded as identical to
30.221 + * +0; otherwise they are considered distinct
30.222 + * @return true if this number fits into a Java long
30.223 + */
30.224 + boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
30.225 + // Figure out if the result will fit in a long. We have to
30.226 + // first look for nonzero digits after the decimal point;
30.227 + // then check the size. If the digit count is 18 or less, then
30.228 + // the value can definitely be represented as a long. If it is 19
30.229 + // then it may be too large.
30.230 +
30.231 + // Trim trailing zeros. This does not change the represented value.
30.232 + while (count > 0 && digits[count - 1] == '0') {
30.233 + --count;
30.234 + }
30.235 +
30.236 + if (count == 0) {
30.237 + // Positive zero fits into a long, but negative zero can only
30.238 + // be represented as a double. - bug 4162852
30.239 + return isPositive || ignoreNegativeZero;
30.240 + }
30.241 +
30.242 + if (decimalAt < count || decimalAt > MAX_COUNT) {
30.243 + return false;
30.244 + }
30.245 +
30.246 + if (decimalAt < MAX_COUNT) return true;
30.247 +
30.248 + // At this point we have decimalAt == count, and count == MAX_COUNT.
30.249 + // The number will overflow if it is larger than 9223372036854775807
30.250 + // or smaller than -9223372036854775808.
30.251 + for (int i=0; i<count; ++i) {
30.252 + char dig = digits[i], max = LONG_MIN_REP[i];
30.253 + if (dig > max) return false;
30.254 + if (dig < max) return true;
30.255 + }
30.256 +
30.257 + // At this point the first count digits match. If decimalAt is less
30.258 + // than count, then the remaining digits are zero, and we return true.
30.259 + if (count < decimalAt) return true;
30.260 +
30.261 + // Now we have a representation of Long.MIN_VALUE, without the leading
30.262 + // negative sign. If this represents a positive value, then it does
30.263 + // not fit; otherwise it fits.
30.264 + return !isPositive;
30.265 + }
30.266 +
30.267 + /**
30.268 + * Set the digit list to a representation of the given double value.
30.269 + * This method supports fixed-point notation.
30.270 + * @param isNegative Boolean value indicating whether the number is negative.
30.271 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
30.272 + * or a value <= 0.
30.273 + * @param maximumFractionDigits The most fractional digits which should
30.274 + * be converted.
30.275 + */
30.276 + public final void set(boolean isNegative, double source, int maximumFractionDigits) {
30.277 + set(isNegative, source, maximumFractionDigits, true);
30.278 + }
30.279 +
30.280 + /**
30.281 + * Set the digit list to a representation of the given double value.
30.282 + * This method supports both fixed-point and exponential notation.
30.283 + * @param isNegative Boolean value indicating whether the number is negative.
30.284 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
30.285 + * or a value <= 0.
30.286 + * @param maximumDigits The most fractional or total digits which should
30.287 + * be converted.
30.288 + * @param fixedPoint If true, then maximumDigits is the maximum
30.289 + * fractional digits to be converted. If false, total digits.
30.290 + */
30.291 + final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
30.292 + set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
30.293 + }
30.294 +
30.295 + /**
30.296 + * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
30.297 + * DDDDDE+/-DDDDD.
30.298 + */
30.299 + final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
30.300 + this.isNegative = isNegative;
30.301 + int len = s.length();
30.302 + char[] source = getDataChars(len);
30.303 + s.getChars(0, len, source, 0);
30.304 +
30.305 + decimalAt = -1;
30.306 + count = 0;
30.307 + int exponent = 0;
30.308 + // Number of zeros between decimal point and first non-zero digit after
30.309 + // decimal point, for numbers < 1.
30.310 + int leadingZerosAfterDecimal = 0;
30.311 + boolean nonZeroDigitSeen = false;
30.312 +
30.313 + for (int i = 0; i < len; ) {
30.314 + char c = source[i++];
30.315 + if (c == '.') {
30.316 + decimalAt = count;
30.317 + } else if (c == 'e' || c == 'E') {
30.318 + exponent = parseInt(source, i, len);
30.319 + break;
30.320 + } else {
30.321 + if (!nonZeroDigitSeen) {
30.322 + nonZeroDigitSeen = (c != '0');
30.323 + if (!nonZeroDigitSeen && decimalAt != -1)
30.324 + ++leadingZerosAfterDecimal;
30.325 + }
30.326 + if (nonZeroDigitSeen) {
30.327 + digits[count++] = c;
30.328 + }
30.329 + }
30.330 + }
30.331 + if (decimalAt == -1) {
30.332 + decimalAt = count;
30.333 + }
30.334 + if (nonZeroDigitSeen) {
30.335 + decimalAt += exponent - leadingZerosAfterDecimal;
30.336 + }
30.337 +
30.338 + if (fixedPoint) {
30.339 + // The negative of the exponent represents the number of leading
30.340 + // zeros between the decimal and the first non-zero digit, for
30.341 + // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
30.342 + // is more than the maximum fraction digits, then we have an underflow
30.343 + // for the printed representation.
30.344 + if (-decimalAt > maximumDigits) {
30.345 + // Handle an underflow to zero when we round something like
30.346 + // 0.0009 to 2 fractional digits.
30.347 + count = 0;
30.348 + return;
30.349 + } else if (-decimalAt == maximumDigits) {
30.350 + // If we round 0.0009 to 3 fractional digits, then we have to
30.351 + // create a new one digit in the least significant location.
30.352 + if (shouldRoundUp(0)) {
30.353 + count = 1;
30.354 + ++decimalAt;
30.355 + digits[0] = '1';
30.356 + } else {
30.357 + count = 0;
30.358 + }
30.359 + return;
30.360 + }
30.361 + // else fall through
30.362 + }
30.363 +
30.364 + // Eliminate trailing zeros.
30.365 + while (count > 1 && digits[count - 1] == '0') {
30.366 + --count;
30.367 + }
30.368 +
30.369 + // Eliminate digits beyond maximum digits to be displayed.
30.370 + // Round up if appropriate.
30.371 + round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
30.372 + }
30.373 +
30.374 + /**
30.375 + * Round the representation to the given number of digits.
30.376 + * @param maximumDigits The maximum number of digits to be shown.
30.377 + * Upon return, count will be less than or equal to maximumDigits.
30.378 + */
30.379 + private final void round(int maximumDigits) {
30.380 + // Eliminate digits beyond maximum digits to be displayed.
30.381 + // Round up if appropriate.
30.382 + if (maximumDigits >= 0 && maximumDigits < count) {
30.383 + if (shouldRoundUp(maximumDigits)) {
30.384 + // Rounding up involved incrementing digits from LSD to MSD.
30.385 + // In most cases this is simple, but in a worst case situation
30.386 + // (9999..99) we have to adjust the decimalAt value.
30.387 + for (;;) {
30.388 + --maximumDigits;
30.389 + if (maximumDigits < 0) {
30.390 + // We have all 9's, so we increment to a single digit
30.391 + // of one and adjust the exponent.
30.392 + digits[0] = '1';
30.393 + ++decimalAt;
30.394 + maximumDigits = 0; // Adjust the count
30.395 + break;
30.396 + }
30.397 +
30.398 + ++digits[maximumDigits];
30.399 + if (digits[maximumDigits] <= '9') break;
30.400 + // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
30.401 + }
30.402 + ++maximumDigits; // Increment for use as count
30.403 + }
30.404 + count = maximumDigits;
30.405 +
30.406 + // Eliminate trailing zeros.
30.407 + while (count > 1 && digits[count-1] == '0') {
30.408 + --count;
30.409 + }
30.410 + }
30.411 + }
30.412 +
30.413 +
30.414 + /**
30.415 + * Return true if truncating the representation to the given number
30.416 + * of digits will result in an increment to the last digit. This
30.417 + * method implements the rounding modes defined in the
30.418 + * java.math.RoundingMode class.
30.419 + * [bnf]
30.420 + * @param maximumDigits the number of digits to keep, from 0 to
30.421 + * <code>count-1</code>. If 0, then all digits are rounded away, and
30.422 + * this method returns true if a one should be generated (e.g., formatting
30.423 + * 0.09 with "#.#").
30.424 + * @exception ArithmeticException if rounding is needed with rounding
30.425 + * mode being set to RoundingMode.UNNECESSARY
30.426 + * @return true if digit <code>maximumDigits-1</code> should be
30.427 + * incremented
30.428 + */
30.429 + private boolean shouldRoundUp(int maximumDigits) {
30.430 + if (maximumDigits < count) {
30.431 + switch(roundingMode) {
30.432 + case UP:
30.433 + for (int i=maximumDigits; i<count; ++i) {
30.434 + if (digits[i] != '0') {
30.435 + return true;
30.436 + }
30.437 + }
30.438 + break;
30.439 + case DOWN:
30.440 + break;
30.441 + case CEILING:
30.442 + for (int i=maximumDigits; i<count; ++i) {
30.443 + if (digits[i] != '0') {
30.444 + return !isNegative;
30.445 + }
30.446 + }
30.447 + break;
30.448 + case FLOOR:
30.449 + for (int i=maximumDigits; i<count; ++i) {
30.450 + if (digits[i] != '0') {
30.451 + return isNegative;
30.452 + }
30.453 + }
30.454 + break;
30.455 + case HALF_UP:
30.456 + if (digits[maximumDigits] >= '5') {
30.457 + return true;
30.458 + }
30.459 + break;
30.460 + case HALF_DOWN:
30.461 + if (digits[maximumDigits] > '5') {
30.462 + return true;
30.463 + } else if (digits[maximumDigits] == '5' ) {
30.464 + for (int i=maximumDigits+1; i<count; ++i) {
30.465 + if (digits[i] != '0') {
30.466 + return true;
30.467 + }
30.468 + }
30.469 + }
30.470 + break;
30.471 + case HALF_EVEN:
30.472 + // Implement IEEE half-even rounding
30.473 + if (digits[maximumDigits] > '5') {
30.474 + return true;
30.475 + } else if (digits[maximumDigits] == '5' ) {
30.476 + for (int i=maximumDigits+1; i<count; ++i) {
30.477 + if (digits[i] != '0') {
30.478 + return true;
30.479 + }
30.480 + }
30.481 + return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
30.482 + }
30.483 + break;
30.484 + case UNNECESSARY:
30.485 + for (int i=maximumDigits; i<count; ++i) {
30.486 + if (digits[i] != '0') {
30.487 + throw new ArithmeticException(
30.488 + "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
30.489 + }
30.490 + }
30.491 + break;
30.492 + default:
30.493 + assert false;
30.494 + }
30.495 + }
30.496 + return false;
30.497 + }
30.498 +
30.499 + /**
30.500 + * Utility routine to set the value of the digit list from a long
30.501 + */
30.502 + public final void set(boolean isNegative, long source) {
30.503 + set(isNegative, source, 0);
30.504 + }
30.505 +
30.506 + /**
30.507 + * Set the digit list to a representation of the given long value.
30.508 + * @param isNegative Boolean value indicating whether the number is negative.
30.509 + * @param source Value to be converted; must be >= 0 or ==
30.510 + * Long.MIN_VALUE.
30.511 + * @param maximumDigits The most digits which should be converted.
30.512 + * If maximumDigits is lower than the number of significant digits
30.513 + * in source, the representation will be rounded. Ignored if <= 0.
30.514 + */
30.515 + public final void set(boolean isNegative, long source, int maximumDigits) {
30.516 + this.isNegative = isNegative;
30.517 +
30.518 + // This method does not expect a negative number. However,
30.519 + // "source" can be a Long.MIN_VALUE (-9223372036854775808),
30.520 + // if the number being formatted is a Long.MIN_VALUE. In that
30.521 + // case, it will be formatted as -Long.MIN_VALUE, a number
30.522 + // which is outside the legal range of a long, but which can
30.523 + // be represented by DigitList.
30.524 + if (source <= 0) {
30.525 + if (source == Long.MIN_VALUE) {
30.526 + decimalAt = count = MAX_COUNT;
30.527 + System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
30.528 + } else {
30.529 + decimalAt = count = 0; // Values <= 0 format as zero
30.530 + }
30.531 + } else {
30.532 + // Rewritten to improve performance. I used to call
30.533 + // Long.toString(), which was about 4x slower than this code.
30.534 + int left = MAX_COUNT;
30.535 + int right;
30.536 + while (source > 0) {
30.537 + digits[--left] = (char)('0' + (source % 10));
30.538 + source /= 10;
30.539 + }
30.540 + decimalAt = MAX_COUNT - left;
30.541 + // Don't copy trailing zeros. We are guaranteed that there is at
30.542 + // least one non-zero digit, so we don't have to check lower bounds.
30.543 + for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
30.544 + ;
30.545 + count = right - left + 1;
30.546 + System.arraycopy(digits, left, digits, 0, count);
30.547 + }
30.548 + if (maximumDigits > 0) round(maximumDigits);
30.549 + }
30.550 +
30.551 + /**
30.552 + * Set the digit list to a representation of the given BigDecimal value.
30.553 + * This method supports both fixed-point and exponential notation.
30.554 + * @param isNegative Boolean value indicating whether the number is negative.
30.555 + * @param source Value to be converted; must not be a value <= 0.
30.556 + * @param maximumDigits The most fractional or total digits which should
30.557 + * be converted.
30.558 + * @param fixedPoint If true, then maximumDigits is the maximum
30.559 + * fractional digits to be converted. If false, total digits.
30.560 + */
30.561 + final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
30.562 + String s = source.toString();
30.563 + extendDigits(s.length());
30.564 +
30.565 + set(isNegative, s, maximumDigits, fixedPoint);
30.566 + }
30.567 +
30.568 + /**
30.569 + * Set the digit list to a representation of the given BigInteger value.
30.570 + * @param isNegative Boolean value indicating whether the number is negative.
30.571 + * @param source Value to be converted; must be >= 0.
30.572 + * @param maximumDigits The most digits which should be converted.
30.573 + * If maximumDigits is lower than the number of significant digits
30.574 + * in source, the representation will be rounded. Ignored if <= 0.
30.575 + */
30.576 + final void set(boolean isNegative, BigInteger source, int maximumDigits) {
30.577 + this.isNegative = isNegative;
30.578 + String s = source.toString();
30.579 + int len = s.length();
30.580 + extendDigits(len);
30.581 + s.getChars(0, len, digits, 0);
30.582 +
30.583 + decimalAt = len;
30.584 + int right;
30.585 + for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
30.586 + ;
30.587 + count = right + 1;
30.588 +
30.589 + if (maximumDigits > 0) {
30.590 + round(maximumDigits);
30.591 + }
30.592 + }
30.593 +
30.594 + /**
30.595 + * equality test between two digit lists.
30.596 + */
30.597 + public boolean equals(Object obj) {
30.598 + if (this == obj) // quick check
30.599 + return true;
30.600 + if (!(obj instanceof DigitList)) // (1) same object?
30.601 + return false;
30.602 + DigitList other = (DigitList) obj;
30.603 + if (count != other.count ||
30.604 + decimalAt != other.decimalAt)
30.605 + return false;
30.606 + for (int i = 0; i < count; i++)
30.607 + if (digits[i] != other.digits[i])
30.608 + return false;
30.609 + return true;
30.610 + }
30.611 +
30.612 + /**
30.613 + * Generates the hash code for the digit list.
30.614 + */
30.615 + public int hashCode() {
30.616 + int hashcode = decimalAt;
30.617 +
30.618 + for (int i = 0; i < count; i++) {
30.619 + hashcode = hashcode * 37 + digits[i];
30.620 + }
30.621 +
30.622 + return hashcode;
30.623 + }
30.624 +
30.625 + /**
30.626 + * Creates a copy of this object.
30.627 + * @return a clone of this instance.
30.628 + */
30.629 + public Object clone() {
30.630 + try {
30.631 + DigitList other = (DigitList) super.clone();
30.632 + char[] newDigits = new char[digits.length];
30.633 + System.arraycopy(digits, 0, newDigits, 0, digits.length);
30.634 + other.digits = newDigits;
30.635 + other.tempBuffer = null;
30.636 + return other;
30.637 + } catch (CloneNotSupportedException e) {
30.638 + throw new InternalError();
30.639 + }
30.640 + }
30.641 +
30.642 + /**
30.643 + * Returns true if this DigitList represents Long.MIN_VALUE;
30.644 + * false, otherwise. This is required so that getLong() works.
30.645 + */
30.646 + private boolean isLongMIN_VALUE() {
30.647 + if (decimalAt != count || count != MAX_COUNT) {
30.648 + return false;
30.649 + }
30.650 +
30.651 + for (int i = 0; i < count; ++i) {
30.652 + if (digits[i] != LONG_MIN_REP[i]) return false;
30.653 + }
30.654 +
30.655 + return true;
30.656 + }
30.657 +
30.658 + private static final int parseInt(char[] str, int offset, int strLen) {
30.659 + char c;
30.660 + boolean positive = true;
30.661 + if ((c = str[offset]) == '-') {
30.662 + positive = false;
30.663 + offset++;
30.664 + } else if (c == '+') {
30.665 + offset++;
30.666 + }
30.667 +
30.668 + int value = 0;
30.669 + while (offset < strLen) {
30.670 + c = str[offset++];
30.671 + if (c >= '0' && c <= '9') {
30.672 + value = value * 10 + (c - '0');
30.673 + } else {
30.674 + break;
30.675 + }
30.676 + }
30.677 + return positive ? value : -value;
30.678 + }
30.679 +
30.680 + // The digit part of -9223372036854775808L
30.681 + private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
30.682 +
30.683 + public String toString() {
30.684 + if (isZero()) {
30.685 + return "0";
30.686 + }
30.687 + StringBuffer buf = getStringBuffer();
30.688 + buf.append("0.");
30.689 + buf.append(digits, 0, count);
30.690 + buf.append("x10^");
30.691 + buf.append(decimalAt);
30.692 + return buf.toString();
30.693 + }
30.694 +
30.695 + private StringBuffer tempBuffer;
30.696 +
30.697 + private StringBuffer getStringBuffer() {
30.698 + if (tempBuffer == null) {
30.699 + tempBuffer = new StringBuffer(MAX_COUNT);
30.700 + } else {
30.701 + tempBuffer.setLength(0);
30.702 + }
30.703 + return tempBuffer;
30.704 + }
30.705 +
30.706 + private void extendDigits(int len) {
30.707 + if (len > digits.length) {
30.708 + digits = new char[len];
30.709 + }
30.710 + }
30.711 +
30.712 + private final char[] getDataChars(int length) {
30.713 + if (data == null || data.length < length) {
30.714 + data = new char[length];
30.715 + }
30.716 + return data;
30.717 + }
30.718 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/rt/emul/compact/src/main/java/java/text/DontCareFieldPosition.java Thu Oct 03 15:40:35 2013 +0200
31.3 @@ -0,0 +1,53 @@
31.4 +/*
31.5 + * Copyright (c) 2002, 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 +package java.text;
31.30 +
31.31 +/**
31.32 + * DontCareFieldPosition defines no-op FieldDelegate. Its
31.33 + * singleton is used for the format methods that don't take a
31.34 + * FieldPosition.
31.35 + */
31.36 +class DontCareFieldPosition extends FieldPosition {
31.37 + // The singleton of DontCareFieldPosition.
31.38 + static final FieldPosition INSTANCE = new DontCareFieldPosition();
31.39 +
31.40 + private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
31.41 + public void formatted(Format.Field attr, Object value, int start,
31.42 + int end, StringBuffer buffer) {
31.43 + }
31.44 + public void formatted(int fieldID, Format.Field attr, Object value,
31.45 + int start, int end, StringBuffer buffer) {
31.46 + }
31.47 + };
31.48 +
31.49 + private DontCareFieldPosition() {
31.50 + super(0);
31.51 + }
31.52 +
31.53 + Format.FieldDelegate getFieldDelegate() {
31.54 + return noDelegate;
31.55 + }
31.56 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/rt/emul/compact/src/main/java/java/text/FieldPosition.java Thu Oct 03 15:40:35 2013 +0200
32.3 @@ -0,0 +1,303 @@
32.4 +/*
32.5 + * Copyright (c) 1996, 2002, 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 - All Rights Reserved
32.31 + * (C) Copyright IBM Corp. 1996 - 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 +/**
32.45 + * <code>FieldPosition</code> is a simple class used by <code>Format</code>
32.46 + * and its subclasses to identify fields in formatted output. Fields can
32.47 + * be identified in two ways:
32.48 + * <ul>
32.49 + * <li>By an integer constant, whose names typically end with
32.50 + * <code>_FIELD</code>. The constants are defined in the various
32.51 + * subclasses of <code>Format</code>.
32.52 + * <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
32.53 + * and its friends in <code>DateFormat</code> for an example.
32.54 + * </ul>
32.55 + * <p>
32.56 + * <code>FieldPosition</code> keeps track of the position of the
32.57 + * field within the formatted output with two indices: the index
32.58 + * of the first character of the field and the index of the last
32.59 + * character of the field.
32.60 + *
32.61 + * <p>
32.62 + * One version of the <code>format</code> method in the various
32.63 + * <code>Format</code> classes requires a <code>FieldPosition</code>
32.64 + * object as an argument. You use this <code>format</code> method
32.65 + * to perform partial formatting or to get information about the
32.66 + * formatted output (such as the position of a field).
32.67 + *
32.68 + * <p>
32.69 + * If you are interested in the positions of all attributes in the
32.70 + * formatted string use the <code>Format</code> method
32.71 + * <code>formatToCharacterIterator</code>.
32.72 + *
32.73 + * @author Mark Davis
32.74 + * @see java.text.Format
32.75 + */
32.76 +public class FieldPosition {
32.77 +
32.78 + /**
32.79 + * Input: Desired field to determine start and end offsets for.
32.80 + * The meaning depends on the subclass of Format.
32.81 + */
32.82 + int field = 0;
32.83 +
32.84 + /**
32.85 + * Output: End offset of field in text.
32.86 + * If the field does not occur in the text, 0 is returned.
32.87 + */
32.88 + int endIndex = 0;
32.89 +
32.90 + /**
32.91 + * Output: Start offset of field in text.
32.92 + * If the field does not occur in the text, 0 is returned.
32.93 + */
32.94 + int beginIndex = 0;
32.95 +
32.96 + /**
32.97 + * Desired field this FieldPosition is for.
32.98 + */
32.99 + private Format.Field attribute;
32.100 +
32.101 + /**
32.102 + * Creates a FieldPosition object for the given field. Fields are
32.103 + * identified by constants, whose names typically end with _FIELD,
32.104 + * in the various subclasses of Format.
32.105 + *
32.106 + * @see java.text.NumberFormat#INTEGER_FIELD
32.107 + * @see java.text.NumberFormat#FRACTION_FIELD
32.108 + * @see java.text.DateFormat#YEAR_FIELD
32.109 + * @see java.text.DateFormat#MONTH_FIELD
32.110 + */
32.111 + public FieldPosition(int field) {
32.112 + this.field = field;
32.113 + }
32.114 +
32.115 + /**
32.116 + * Creates a FieldPosition object for the given field constant. Fields are
32.117 + * identified by constants defined in the various <code>Format</code>
32.118 + * subclasses. This is equivalent to calling
32.119 + * <code>new FieldPosition(attribute, -1)</code>.
32.120 + *
32.121 + * @param attribute Format.Field constant identifying a field
32.122 + * @since 1.4
32.123 + */
32.124 + public FieldPosition(Format.Field attribute) {
32.125 + this(attribute, -1);
32.126 + }
32.127 +
32.128 + /**
32.129 + * Creates a <code>FieldPosition</code> object for the given field.
32.130 + * The field is identified by an attribute constant from one of the
32.131 + * <code>Field</code> subclasses as well as an integer field ID
32.132 + * defined by the <code>Format</code> subclasses. <code>Format</code>
32.133 + * subclasses that are aware of <code>Field</code> should give precedence
32.134 + * to <code>attribute</code> and ignore <code>fieldID</code> if
32.135 + * <code>attribute</code> is not null. However, older <code>Format</code>
32.136 + * subclasses may not be aware of <code>Field</code> and rely on
32.137 + * <code>fieldID</code>. If the field has no corresponding integer
32.138 + * constant, <code>fieldID</code> should be -1.
32.139 + *
32.140 + * @param attribute Format.Field constant identifying a field
32.141 + * @param fieldID integer constantce identifying a field
32.142 + * @since 1.4
32.143 + */
32.144 + public FieldPosition(Format.Field attribute, int fieldID) {
32.145 + this.attribute = attribute;
32.146 + this.field = fieldID;
32.147 + }
32.148 +
32.149 + /**
32.150 + * Returns the field identifier as an attribute constant
32.151 + * from one of the <code>Field</code> subclasses. May return null if
32.152 + * the field is specified only by an integer field ID.
32.153 + *
32.154 + * @return Identifier for the field
32.155 + * @since 1.4
32.156 + */
32.157 + public Format.Field getFieldAttribute() {
32.158 + return attribute;
32.159 + }
32.160 +
32.161 + /**
32.162 + * Retrieves the field identifier.
32.163 + */
32.164 + public int getField() {
32.165 + return field;
32.166 + }
32.167 +
32.168 + /**
32.169 + * Retrieves the index of the first character in the requested field.
32.170 + */
32.171 + public int getBeginIndex() {
32.172 + return beginIndex;
32.173 + }
32.174 +
32.175 + /**
32.176 + * Retrieves the index of the character following the last character in the
32.177 + * requested field.
32.178 + */
32.179 + public int getEndIndex() {
32.180 + return endIndex;
32.181 + }
32.182 +
32.183 + /**
32.184 + * Sets the begin index. For use by subclasses of Format.
32.185 + * @since 1.2
32.186 + */
32.187 + public void setBeginIndex(int bi) {
32.188 + beginIndex = bi;
32.189 + }
32.190 +
32.191 + /**
32.192 + * Sets the end index. For use by subclasses of Format.
32.193 + * @since 1.2
32.194 + */
32.195 + public void setEndIndex(int ei) {
32.196 + endIndex = ei;
32.197 + }
32.198 +
32.199 + /**
32.200 + * Returns a <code>Format.FieldDelegate</code> instance that is associated
32.201 + * with the FieldPosition. When the delegate is notified of the same
32.202 + * field the FieldPosition is associated with, the begin/end will be
32.203 + * adjusted.
32.204 + */
32.205 + Format.FieldDelegate getFieldDelegate() {
32.206 + return new Delegate();
32.207 + }
32.208 +
32.209 + /**
32.210 + * Overrides equals
32.211 + */
32.212 + public boolean equals(Object obj)
32.213 + {
32.214 + if (obj == null) return false;
32.215 + if (!(obj instanceof FieldPosition))
32.216 + return false;
32.217 + FieldPosition other = (FieldPosition) obj;
32.218 + if (attribute == null) {
32.219 + if (other.attribute != null) {
32.220 + return false;
32.221 + }
32.222 + }
32.223 + else if (!attribute.equals(other.attribute)) {
32.224 + return false;
32.225 + }
32.226 + return (beginIndex == other.beginIndex
32.227 + && endIndex == other.endIndex
32.228 + && field == other.field);
32.229 + }
32.230 +
32.231 + /**
32.232 + * Returns a hash code for this FieldPosition.
32.233 + * @return a hash code value for this object
32.234 + */
32.235 + public int hashCode() {
32.236 + return (field << 24) | (beginIndex << 16) | endIndex;
32.237 + }
32.238 +
32.239 + /**
32.240 + * Return a string representation of this FieldPosition.
32.241 + * @return a string representation of this object
32.242 + */
32.243 + public String toString() {
32.244 + return getClass().getName() +
32.245 + "[field=" + field + ",attribute=" + attribute +
32.246 + ",beginIndex=" + beginIndex +
32.247 + ",endIndex=" + endIndex + ']';
32.248 + }
32.249 +
32.250 +
32.251 + /**
32.252 + * Return true if the receiver wants a <code>Format.Field</code> value and
32.253 + * <code>attribute</code> is equal to it.
32.254 + */
32.255 + private boolean matchesField(Format.Field attribute) {
32.256 + if (this.attribute != null) {
32.257 + return this.attribute.equals(attribute);
32.258 + }
32.259 + return false;
32.260 + }
32.261 +
32.262 + /**
32.263 + * Return true if the receiver wants a <code>Format.Field</code> value and
32.264 + * <code>attribute</code> is equal to it, or true if the receiver
32.265 + * represents an inteter constant and <code>field</code> equals it.
32.266 + */
32.267 + private boolean matchesField(Format.Field attribute, int field) {
32.268 + if (this.attribute != null) {
32.269 + return this.attribute.equals(attribute);
32.270 + }
32.271 + return (field == this.field);
32.272 + }
32.273 +
32.274 +
32.275 + /**
32.276 + * An implementation of FieldDelegate that will adjust the begin/end
32.277 + * of the FieldPosition if the arguments match the field of
32.278 + * the FieldPosition.
32.279 + */
32.280 + private class Delegate implements Format.FieldDelegate {
32.281 + /**
32.282 + * Indicates whether the field has been encountered before. If this
32.283 + * is true, and <code>formatted</code> is invoked, the begin/end
32.284 + * are not updated.
32.285 + */
32.286 + private boolean encounteredField;
32.287 +
32.288 + public void formatted(Format.Field attr, Object value, int start,
32.289 + int end, StringBuffer buffer) {
32.290 + if (!encounteredField && matchesField(attr)) {
32.291 + setBeginIndex(start);
32.292 + setEndIndex(end);
32.293 + encounteredField = (start != end);
32.294 + }
32.295 + }
32.296 +
32.297 + public void formatted(int fieldID, Format.Field attr, Object value,
32.298 + int start, int end, StringBuffer buffer) {
32.299 + if (!encounteredField && matchesField(attr, fieldID)) {
32.300 + setBeginIndex(start);
32.301 + setEndIndex(end);
32.302 + encounteredField = (start != end);
32.303 + }
32.304 + }
32.305 + }
32.306 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/rt/emul/compact/src/main/java/java/text/Format.java Thu Oct 03 15:40:35 2013 +0200
33.3 @@ -0,0 +1,406 @@
33.4 +/*
33.5 + * Copyright (c) 1996, 2005, 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 +/*
33.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
33.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
33.32 + *
33.33 + * The original version of this source code and documentation is copyrighted
33.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
33.35 + * materials are provided under terms of a License Agreement between Taligent
33.36 + * and Sun. This technology is protected by multiple US and International
33.37 + * patents. This notice and attribution to Taligent may not be removed.
33.38 + * Taligent is a registered trademark of Taligent, Inc.
33.39 + *
33.40 + */
33.41 +
33.42 +package java.text;
33.43 +
33.44 +import java.io.Serializable;
33.45 +
33.46 +/**
33.47 + * <code>Format</code> is an abstract base class for formatting locale-sensitive
33.48 + * information such as dates, messages, and numbers.
33.49 + *
33.50 + * <p>
33.51 + * <code>Format</code> defines the programming interface for formatting
33.52 + * locale-sensitive objects into <code>String</code>s (the
33.53 + * <code>format</code> method) and for parsing <code>String</code>s back
33.54 + * into objects (the <code>parseObject</code> method).
33.55 + *
33.56 + * <p>
33.57 + * Generally, a format's <code>parseObject</code> method must be able to parse
33.58 + * any string formatted by its <code>format</code> method. However, there may
33.59 + * be exceptional cases where this is not possible. For example, a
33.60 + * <code>format</code> method might create two adjacent integer numbers with
33.61 + * no separator in between, and in this case the <code>parseObject</code> could
33.62 + * not tell which digits belong to which number.
33.63 + *
33.64 + * <h4>Subclassing</h4>
33.65 + *
33.66 + * <p>
33.67 + * The Java Platform provides three specialized subclasses of <code>Format</code>--
33.68 + * <code>DateFormat</code>, <code>MessageFormat</code>, and
33.69 + * <code>NumberFormat</code>--for formatting dates, messages, and numbers,
33.70 + * respectively.
33.71 + * <p>
33.72 + * Concrete subclasses must implement three methods:
33.73 + * <ol>
33.74 + * <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
33.75 + * <li> <code>formatToCharacterIterator(Object obj)</code>
33.76 + * <li> <code>parseObject(String source, ParsePosition pos)</code>
33.77 + * </ol>
33.78 + * These general methods allow polymorphic parsing and formatting of objects
33.79 + * and are used, for example, by <code>MessageFormat</code>.
33.80 + * Subclasses often also provide additional <code>format</code> methods for
33.81 + * specific input types as well as <code>parse</code> methods for specific
33.82 + * result types. Any <code>parse</code> method that does not take a
33.83 + * <code>ParsePosition</code> argument should throw <code>ParseException</code>
33.84 + * when no text in the required format is at the beginning of the input text.
33.85 + *
33.86 + * <p>
33.87 + * Most subclasses will also implement the following factory methods:
33.88 + * <ol>
33.89 + * <li>
33.90 + * <code>getInstance</code> for getting a useful format object appropriate
33.91 + * for the current locale
33.92 + * <li>
33.93 + * <code>getInstance(Locale)</code> for getting a useful format
33.94 + * object appropriate for the specified locale
33.95 + * </ol>
33.96 + * In addition, some subclasses may also implement other
33.97 + * <code>getXxxxInstance</code> methods for more specialized control. For
33.98 + * example, the <code>NumberFormat</code> class provides
33.99 + * <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
33.100 + * methods for getting specialized number formatters.
33.101 + *
33.102 + * <p>
33.103 + * Subclasses of <code>Format</code> that allow programmers to create objects
33.104 + * for locales (with <code>getInstance(Locale)</code> for example)
33.105 + * must also implement the following class method:
33.106 + * <blockquote>
33.107 + * <pre>
33.108 + * public static Locale[] getAvailableLocales()
33.109 + * </pre>
33.110 + * </blockquote>
33.111 + *
33.112 + * <p>
33.113 + * And finally subclasses may define a set of constants to identify the various
33.114 + * fields in the formatted output. These constants are used to create a FieldPosition
33.115 + * object which identifies what information is contained in the field and its
33.116 + * position in the formatted result. These constants should be named
33.117 + * <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
33.118 + * the field. For examples of these constants, see <code>ERA_FIELD</code> and its
33.119 + * friends in {@link DateFormat}.
33.120 + *
33.121 + * <h4><a name="synchronization">Synchronization</a></h4>
33.122 + *
33.123 + * <p>
33.124 + * Formats are generally not synchronized.
33.125 + * It is recommended to create separate format instances for each thread.
33.126 + * If multiple threads access a format concurrently, it must be synchronized
33.127 + * externally.
33.128 + *
33.129 + * @see java.text.ParsePosition
33.130 + * @see java.text.FieldPosition
33.131 + * @see java.text.NumberFormat
33.132 + * @see java.text.DateFormat
33.133 + * @see java.text.MessageFormat
33.134 + * @author Mark Davis
33.135 + */
33.136 +public abstract class Format implements Serializable, Cloneable {
33.137 +
33.138 + private static final long serialVersionUID = -299282585814624189L;
33.139 +
33.140 + /**
33.141 + * Sole constructor. (For invocation by subclass constructors, typically
33.142 + * implicit.)
33.143 + */
33.144 + protected Format() {
33.145 + }
33.146 +
33.147 + /**
33.148 + * Formats an object to produce a string. This is equivalent to
33.149 + * <blockquote>
33.150 + * {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
33.151 + * new StringBuffer(), new FieldPosition(0)).toString();</code>
33.152 + * </blockquote>
33.153 + *
33.154 + * @param obj The object to format
33.155 + * @return Formatted string.
33.156 + * @exception IllegalArgumentException if the Format cannot format the given
33.157 + * object
33.158 + */
33.159 + public final String format (Object obj) {
33.160 + return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
33.161 + }
33.162 +
33.163 + /**
33.164 + * Formats an object and appends the resulting text to a given string
33.165 + * buffer.
33.166 + * If the <code>pos</code> argument identifies a field used by the format,
33.167 + * then its indices are set to the beginning and end of the first such
33.168 + * field encountered.
33.169 + *
33.170 + * @param obj The object to format
33.171 + * @param toAppendTo where the text is to be appended
33.172 + * @param pos A <code>FieldPosition</code> identifying a field
33.173 + * in the formatted text
33.174 + * @return the string buffer passed in as <code>toAppendTo</code>,
33.175 + * with formatted text appended
33.176 + * @exception NullPointerException if <code>toAppendTo</code> or
33.177 + * <code>pos</code> is null
33.178 + * @exception IllegalArgumentException if the Format cannot format the given
33.179 + * object
33.180 + */
33.181 + public abstract StringBuffer format(Object obj,
33.182 + StringBuffer toAppendTo,
33.183 + FieldPosition pos);
33.184 +
33.185 + /**
33.186 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
33.187 + * You can use the returned <code>AttributedCharacterIterator</code>
33.188 + * to build the resulting String, as well as to determine information
33.189 + * about the resulting String.
33.190 + * <p>
33.191 + * Each attribute key of the AttributedCharacterIterator will be of type
33.192 + * <code>Field</code>. It is up to each <code>Format</code> implementation
33.193 + * to define what the legal values are for each attribute in the
33.194 + * <code>AttributedCharacterIterator</code>, but typically the attribute
33.195 + * key is also used as the attribute value.
33.196 + * <p>The default implementation creates an
33.197 + * <code>AttributedCharacterIterator</code> with no attributes. Subclasses
33.198 + * that support fields should override this and create an
33.199 + * <code>AttributedCharacterIterator</code> with meaningful attributes.
33.200 + *
33.201 + * @exception NullPointerException if obj is null.
33.202 + * @exception IllegalArgumentException when the Format cannot format the
33.203 + * given object.
33.204 + * @param obj The object to format
33.205 + * @return AttributedCharacterIterator describing the formatted value.
33.206 + * @since 1.4
33.207 + */
33.208 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
33.209 + return createAttributedCharacterIterator(format(obj));
33.210 + }
33.211 +
33.212 + /**
33.213 + * Parses text from a string to produce an object.
33.214 + * <p>
33.215 + * The method attempts to parse text starting at the index given by
33.216 + * <code>pos</code>.
33.217 + * If parsing succeeds, then the index of <code>pos</code> is updated
33.218 + * to the index after the last character used (parsing does not necessarily
33.219 + * use all characters up to the end of the string), and the parsed
33.220 + * object is returned. The updated <code>pos</code> can be used to
33.221 + * indicate the starting point for the next call to this method.
33.222 + * If an error occurs, then the index of <code>pos</code> is not
33.223 + * changed, the error index of <code>pos</code> is set to the index of
33.224 + * the character where the error occurred, and null is returned.
33.225 + *
33.226 + * @param source A <code>String</code>, part of which should be parsed.
33.227 + * @param pos A <code>ParsePosition</code> object with index and error
33.228 + * index information as described above.
33.229 + * @return An <code>Object</code> parsed from the string. In case of
33.230 + * error, returns null.
33.231 + * @exception NullPointerException if <code>pos</code> is null.
33.232 + */
33.233 + public abstract Object parseObject (String source, ParsePosition pos);
33.234 +
33.235 + /**
33.236 + * Parses text from the beginning of the given string to produce an object.
33.237 + * The method may not use the entire text of the given string.
33.238 + *
33.239 + * @param source A <code>String</code> whose beginning should be parsed.
33.240 + * @return An <code>Object</code> parsed from the string.
33.241 + * @exception ParseException if the beginning of the specified string
33.242 + * cannot be parsed.
33.243 + */
33.244 + public Object parseObject(String source) throws ParseException {
33.245 + ParsePosition pos = new ParsePosition(0);
33.246 + Object result = parseObject(source, pos);
33.247 + if (pos.index == 0) {
33.248 + throw new ParseException("Format.parseObject(String) failed",
33.249 + pos.errorIndex);
33.250 + }
33.251 + return result;
33.252 + }
33.253 +
33.254 + /**
33.255 + * Creates and returns a copy of this object.
33.256 + *
33.257 + * @return a clone of this instance.
33.258 + */
33.259 + public Object clone() {
33.260 + try {
33.261 + return super.clone();
33.262 + } catch (CloneNotSupportedException e) {
33.263 + // will never happen
33.264 + return null;
33.265 + }
33.266 + }
33.267 +
33.268 + //
33.269 + // Convenience methods for creating AttributedCharacterIterators from
33.270 + // different parameters.
33.271 + //
33.272 +
33.273 + /**
33.274 + * Creates an <code>AttributedCharacterIterator</code> for the String
33.275 + * <code>s</code>.
33.276 + *
33.277 + * @param s String to create AttributedCharacterIterator from
33.278 + * @return AttributedCharacterIterator wrapping s
33.279 + */
33.280 + AttributedCharacterIterator createAttributedCharacterIterator(String s) {
33.281 + AttributedString as = new AttributedString(s);
33.282 +
33.283 + return as.getIterator();
33.284 + }
33.285 +
33.286 + /**
33.287 + * Creates an <code>AttributedCharacterIterator</code> containg the
33.288 + * concatenated contents of the passed in
33.289 + * <code>AttributedCharacterIterator</code>s.
33.290 + *
33.291 + * @param iterators AttributedCharacterIterators used to create resulting
33.292 + * AttributedCharacterIterators
33.293 + * @return AttributedCharacterIterator wrapping passed in
33.294 + * AttributedCharacterIterators
33.295 + */
33.296 + AttributedCharacterIterator createAttributedCharacterIterator(
33.297 + AttributedCharacterIterator[] iterators) {
33.298 + AttributedString as = new AttributedString(iterators);
33.299 +
33.300 + return as.getIterator();
33.301 + }
33.302 +
33.303 + /**
33.304 + * Returns an AttributedCharacterIterator with the String
33.305 + * <code>string</code> and additional key/value pair <code>key</code>,
33.306 + * <code>value</code>.
33.307 + *
33.308 + * @param string String to create AttributedCharacterIterator from
33.309 + * @param key Key for AttributedCharacterIterator
33.310 + * @param value Value associated with key in AttributedCharacterIterator
33.311 + * @return AttributedCharacterIterator wrapping args
33.312 + */
33.313 + AttributedCharacterIterator createAttributedCharacterIterator(
33.314 + String string, AttributedCharacterIterator.Attribute key,
33.315 + Object value) {
33.316 + AttributedString as = new AttributedString(string);
33.317 +
33.318 + as.addAttribute(key, value);
33.319 + return as.getIterator();
33.320 + }
33.321 +
33.322 + /**
33.323 + * Creates an AttributedCharacterIterator with the contents of
33.324 + * <code>iterator</code> and the additional attribute <code>key</code>
33.325 + * <code>value</code>.
33.326 + *
33.327 + * @param iterator Initial AttributedCharacterIterator to add arg to
33.328 + * @param key Key for AttributedCharacterIterator
33.329 + * @param value Value associated with key in AttributedCharacterIterator
33.330 + * @return AttributedCharacterIterator wrapping args
33.331 + */
33.332 + AttributedCharacterIterator createAttributedCharacterIterator(
33.333 + AttributedCharacterIterator iterator,
33.334 + AttributedCharacterIterator.Attribute key, Object value) {
33.335 + AttributedString as = new AttributedString(iterator);
33.336 +
33.337 + as.addAttribute(key, value);
33.338 + return as.getIterator();
33.339 + }
33.340 +
33.341 +
33.342 + /**
33.343 + * Defines constants that are used as attribute keys in the
33.344 + * <code>AttributedCharacterIterator</code> returned
33.345 + * from <code>Format.formatToCharacterIterator</code> and as
33.346 + * field identifiers in <code>FieldPosition</code>.
33.347 + *
33.348 + * @since 1.4
33.349 + */
33.350 + public static class Field extends AttributedCharacterIterator.Attribute {
33.351 +
33.352 + // Proclaim serial compatibility with 1.4 FCS
33.353 + private static final long serialVersionUID = 276966692217360283L;
33.354 +
33.355 + /**
33.356 + * Creates a Field with the specified name.
33.357 + *
33.358 + * @param name Name of the attribute
33.359 + */
33.360 + protected Field(String name) {
33.361 + super(name);
33.362 + }
33.363 + }
33.364 +
33.365 +
33.366 + /**
33.367 + * FieldDelegate is notified by the various <code>Format</code>
33.368 + * implementations as they are formatting the Objects. This allows for
33.369 + * storage of the individual sections of the formatted String for
33.370 + * later use, such as in a <code>FieldPosition</code> or for an
33.371 + * <code>AttributedCharacterIterator</code>.
33.372 + * <p>
33.373 + * Delegates should NOT assume that the <code>Format</code> will notify
33.374 + * the delegate of fields in any particular order.
33.375 + *
33.376 + * @see FieldPosition.Delegate
33.377 + * @see CharacterIteratorFieldDelegate
33.378 + */
33.379 + interface FieldDelegate {
33.380 + /**
33.381 + * Notified when a particular region of the String is formatted. This
33.382 + * method will be invoked if there is no corresponding integer field id
33.383 + * matching <code>attr</code>.
33.384 + *
33.385 + * @param attr Identifies the field matched
33.386 + * @param value Value associated with the field
33.387 + * @param start Beginning location of the field, will be >= 0
33.388 + * @param end End of the field, will be >= start and <= buffer.length()
33.389 + * @param buffer Contains current formatted value, receiver should
33.390 + * NOT modify it.
33.391 + */
33.392 + public void formatted(Format.Field attr, Object value, int start,
33.393 + int end, StringBuffer buffer);
33.394 +
33.395 + /**
33.396 + * Notified when a particular region of the String is formatted.
33.397 + *
33.398 + * @param fieldID Identifies the field by integer
33.399 + * @param attr Identifies the field matched
33.400 + * @param value Value associated with the field
33.401 + * @param start Beginning location of the field, will be >= 0
33.402 + * @param end End of the field, will be >= start and <= buffer.length()
33.403 + * @param buffer Contains current formatted value, receiver should
33.404 + * NOT modify it.
33.405 + */
33.406 + public void formatted(int fieldID, Format.Field attr, Object value,
33.407 + int start, int end, StringBuffer buffer);
33.408 + }
33.409 +}
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/rt/emul/compact/src/main/java/java/text/MessageFormat.java Thu Oct 03 15:40:35 2013 +0200
34.3 @@ -0,0 +1,1594 @@
34.4 +/*
34.5 + * Copyright (c) 1996, 2010, 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, 1997 - All Rights Reserved
34.31 + * (C) Copyright IBM Corp. 1996 - 1998 - 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 +import java.io.InvalidObjectException;
34.45 +import java.io.IOException;
34.46 +import java.io.ObjectInputStream;
34.47 +import java.text.DecimalFormat;
34.48 +import java.util.ArrayList;
34.49 +import java.util.Arrays;
34.50 +import java.util.Date;
34.51 +import java.util.List;
34.52 +import java.util.Locale;
34.53 +
34.54 +
34.55 +/**
34.56 + * <code>MessageFormat</code> provides a means to produce concatenated
34.57 + * messages in a language-neutral way. Use this to construct messages
34.58 + * displayed for end users.
34.59 + *
34.60 + * <p>
34.61 + * <code>MessageFormat</code> takes a set of objects, formats them, then
34.62 + * inserts the formatted strings into the pattern at the appropriate places.
34.63 + *
34.64 + * <p>
34.65 + * <strong>Note:</strong>
34.66 + * <code>MessageFormat</code> differs from the other <code>Format</code>
34.67 + * classes in that you create a <code>MessageFormat</code> object with one
34.68 + * of its constructors (not with a <code>getInstance</code> style factory
34.69 + * method). The factory methods aren't necessary because <code>MessageFormat</code>
34.70 + * itself doesn't implement locale specific behavior. Any locale specific
34.71 + * behavior is defined by the pattern that you provide as well as the
34.72 + * subformats used for inserted arguments.
34.73 + *
34.74 + * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
34.75 + *
34.76 + * <code>MessageFormat</code> uses patterns of the following form:
34.77 + * <blockquote><pre>
34.78 + * <i>MessageFormatPattern:</i>
34.79 + * <i>String</i>
34.80 + * <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
34.81 + *
34.82 + * <i>FormatElement:</i>
34.83 + * { <i>ArgumentIndex</i> }
34.84 + * { <i>ArgumentIndex</i> , <i>FormatType</i> }
34.85 + * { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
34.86 + *
34.87 + * <i>FormatType: one of </i>
34.88 + * number date time choice
34.89 + *
34.90 + * <i>FormatStyle:</i>
34.91 + * short
34.92 + * medium
34.93 + * long
34.94 + * full
34.95 + * integer
34.96 + * currency
34.97 + * percent
34.98 + * <i>SubformatPattern</i>
34.99 + * </pre></blockquote>
34.100 + *
34.101 + * <p>Within a <i>String</i>, a pair of single quotes can be used to
34.102 + * quote any arbitrary characters except single quotes. For example,
34.103 + * pattern string <code>"'{0}'"</code> represents string
34.104 + * <code>"{0}"</code>, not a <i>FormatElement</i>. A single quote itself
34.105 + * must be represented by doubled single quotes {@code ''} throughout a
34.106 + * <i>String</i>. For example, pattern string <code>"'{''}'"</code> is
34.107 + * interpreted as a sequence of <code>'{</code> (start of quoting and a
34.108 + * left curly brace), <code>''</code> (a single quote), and
34.109 + * <code>}'</code> (a right curly brace and end of quoting),
34.110 + * <em>not</em> <code>'{'</code> and <code>'}'</code> (quoted left and
34.111 + * right curly braces): representing string <code>"{'}"</code>,
34.112 + * <em>not</em> <code>"{}"</code>.
34.113 + *
34.114 + * <p>A <i>SubformatPattern</i> is interpreted by its corresponding
34.115 + * subformat, and subformat-dependent pattern rules apply. For example,
34.116 + * pattern string <code>"{1,number,<u>$'#',##</u>}"</code>
34.117 + * (<i>SubformatPattern</i> with underline) will produce a number format
34.118 + * with the pound-sign quoted, with a result such as: {@code
34.119 + * "$#31,45"}. Refer to each {@code Format} subclass documentation for
34.120 + * details.
34.121 + *
34.122 + * <p>Any unmatched quote is treated as closed at the end of the given
34.123 + * pattern. For example, pattern string {@code "'{0}"} is treated as
34.124 + * pattern {@code "'{0}'"}.
34.125 + *
34.126 + * <p>Any curly braces within an unquoted pattern must be balanced. For
34.127 + * example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code> are
34.128 + * valid patterns, but <code>"ab {0'}' de"</code>, <code>"ab } de"</code>
34.129 + * and <code>"''{''"</code> are not.
34.130 + *
34.131 + * <p>
34.132 + * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
34.133 + * format patterns unfortunately have shown to be somewhat confusing.
34.134 + * In particular, it isn't always obvious to localizers whether single
34.135 + * quotes need to be doubled or not. Make sure to inform localizers about
34.136 + * the rules, and tell them (for example, by using comments in resource
34.137 + * bundle source files) which strings will be processed by {@code MessageFormat}.
34.138 + * Note that localizers may need to use single quotes in translated
34.139 + * strings where the original version doesn't have them.
34.140 + * </dl>
34.141 + * <p>
34.142 + * The <i>ArgumentIndex</i> value is a non-negative integer written
34.143 + * using the digits {@code '0'} through {@code '9'}, and represents an index into the
34.144 + * {@code arguments} array passed to the {@code format} methods
34.145 + * or the result array returned by the {@code parse} methods.
34.146 + * <p>
34.147 + * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
34.148 + * a {@code Format} instance for the format element. The following
34.149 + * table shows how the values map to {@code Format} instances. Combinations not
34.150 + * shown in the table are illegal. A <i>SubformatPattern</i> must
34.151 + * be a valid pattern string for the {@code Format} subclass used.
34.152 + * <p>
34.153 + * <table border=1 summary="Shows how FormatType and FormatStyle values map to Format instances">
34.154 + * <tr>
34.155 + * <th id="ft" class="TableHeadingColor">FormatType
34.156 + * <th id="fs" class="TableHeadingColor">FormatStyle
34.157 + * <th id="sc" class="TableHeadingColor">Subformat Created
34.158 + * <tr>
34.159 + * <td headers="ft"><i>(none)</i>
34.160 + * <td headers="fs"><i>(none)</i>
34.161 + * <td headers="sc"><code>null</code>
34.162 + * <tr>
34.163 + * <td headers="ft" rowspan=5><code>number</code>
34.164 + * <td headers="fs"><i>(none)</i>
34.165 + * <td headers="sc">{@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())}
34.166 + * <tr>
34.167 + * <td headers="fs"><code>integer</code>
34.168 + * <td headers="sc">{@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())}
34.169 + * <tr>
34.170 + * <td headers="fs"><code>currency</code>
34.171 + * <td headers="sc">{@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())}
34.172 + * <tr>
34.173 + * <td headers="fs"><code>percent</code>
34.174 + * <td headers="sc">{@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())}
34.175 + * <tr>
34.176 + * <td headers="fs"><i>SubformatPattern</i>
34.177 + * <td headers="sc">{@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))}
34.178 + * <tr>
34.179 + * <td headers="ft" rowspan=6><code>date</code>
34.180 + * <td headers="fs"><i>(none)</i>
34.181 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
34.182 + * <tr>
34.183 + * <td headers="fs"><code>short</code>
34.184 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
34.185 + * <tr>
34.186 + * <td headers="fs"><code>medium</code>
34.187 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
34.188 + * <tr>
34.189 + * <td headers="fs"><code>long</code>
34.190 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
34.191 + * <tr>
34.192 + * <td headers="fs"><code>full</code>
34.193 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
34.194 + * <tr>
34.195 + * <td headers="fs"><i>SubformatPattern</i>
34.196 + * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
34.197 + * <tr>
34.198 + * <td headers="ft" rowspan=6><code>time</code>
34.199 + * <td headers="fs"><i>(none)</i>
34.200 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
34.201 + * <tr>
34.202 + * <td headers="fs"><code>short</code>
34.203 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
34.204 + * <tr>
34.205 + * <td headers="fs"><code>medium</code>
34.206 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
34.207 + * <tr>
34.208 + * <td headers="fs"><code>long</code>
34.209 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
34.210 + * <tr>
34.211 + * <td headers="fs"><code>full</code>
34.212 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
34.213 + * <tr>
34.214 + * <td headers="fs"><i>SubformatPattern</i>
34.215 + * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
34.216 + * <tr>
34.217 + * <td headers="ft"><code>choice</code>
34.218 + * <td headers="fs"><i>SubformatPattern</i>
34.219 + * <td headers="sc">{@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)}
34.220 + * </table>
34.221 + * <p>
34.222 + *
34.223 + * <h4>Usage Information</h4>
34.224 + *
34.225 + * <p>
34.226 + * Here are some examples of usage.
34.227 + * In real internationalized programs, the message format pattern and other
34.228 + * static strings will, of course, be obtained from resource bundles.
34.229 + * Other parameters will be dynamically determined at runtime.
34.230 + * <p>
34.231 + * The first example uses the static method <code>MessageFormat.format</code>,
34.232 + * which internally creates a <code>MessageFormat</code> for one-time use:
34.233 + * <blockquote><pre>
34.234 + * int planet = 7;
34.235 + * String event = "a disturbance in the Force";
34.236 + *
34.237 + * String result = MessageFormat.format(
34.238 + * "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
34.239 + * planet, new Date(), event);
34.240 + * </pre></blockquote>
34.241 + * The output is:
34.242 + * <blockquote><pre>
34.243 + * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
34.244 + * </pre></blockquote>
34.245 + *
34.246 + * <p>
34.247 + * The following example creates a <code>MessageFormat</code> instance that
34.248 + * can be used repeatedly:
34.249 + * <blockquote><pre>
34.250 + * int fileCount = 1273;
34.251 + * String diskName = "MyDisk";
34.252 + * Object[] testArgs = {new Long(fileCount), diskName};
34.253 + *
34.254 + * MessageFormat form = new MessageFormat(
34.255 + * "The disk \"{1}\" contains {0} file(s).");
34.256 + *
34.257 + * System.out.println(form.format(testArgs));
34.258 + * </pre></blockquote>
34.259 + * The output with different values for <code>fileCount</code>:
34.260 + * <blockquote><pre>
34.261 + * The disk "MyDisk" contains 0 file(s).
34.262 + * The disk "MyDisk" contains 1 file(s).
34.263 + * The disk "MyDisk" contains 1,273 file(s).
34.264 + * </pre></blockquote>
34.265 + *
34.266 + * <p>
34.267 + * For more sophisticated patterns, you can use a <code>ChoiceFormat</code>
34.268 + * to produce correct forms for singular and plural:
34.269 + * <blockquote><pre>
34.270 + * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
34.271 + * double[] filelimits = {0,1,2};
34.272 + * String[] filepart = {"no files","one file","{0,number} files"};
34.273 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
34.274 + * form.setFormatByArgumentIndex(0, fileform);
34.275 + *
34.276 + * int fileCount = 1273;
34.277 + * String diskName = "MyDisk";
34.278 + * Object[] testArgs = {new Long(fileCount), diskName};
34.279 + *
34.280 + * System.out.println(form.format(testArgs));
34.281 + * </pre></blockquote>
34.282 + * The output with different values for <code>fileCount</code>:
34.283 + * <blockquote><pre>
34.284 + * The disk "MyDisk" contains no files.
34.285 + * The disk "MyDisk" contains one file.
34.286 + * The disk "MyDisk" contains 1,273 files.
34.287 + * </pre></blockquote>
34.288 + *
34.289 + * <p>
34.290 + * You can create the <code>ChoiceFormat</code> programmatically, as in the
34.291 + * above example, or by using a pattern. See {@link ChoiceFormat}
34.292 + * for more information.
34.293 + * <blockquote><pre>
34.294 + * form.applyPattern(
34.295 + * "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");
34.296 + * </pre></blockquote>
34.297 + *
34.298 + * <p>
34.299 + * <strong>Note:</strong> As we see above, the string produced
34.300 + * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated as special;
34.301 + * occurrences of '{' are used to indicate subformats, and cause recursion.
34.302 + * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
34.303 + * programmatically (instead of using the string patterns), then be careful not to
34.304 + * produce a format that recurses on itself, which will cause an infinite loop.
34.305 + * <p>
34.306 + * When a single argument is parsed more than once in the string, the last match
34.307 + * will be the final result of the parsing. For example,
34.308 + * <blockquote><pre>
34.309 + * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
34.310 + * Object[] objs = {new Double(3.1415)};
34.311 + * String result = mf.format( objs );
34.312 + * // result now equals "3.14, 3.1"
34.313 + * objs = null;
34.314 + * objs = mf.parse(result, new ParsePosition(0));
34.315 + * // objs now equals {new Double(3.1)}
34.316 + * </pre></blockquote>
34.317 + *
34.318 + * <p>
34.319 + * Likewise, parsing with a {@code MessageFormat} object using patterns containing
34.320 + * multiple occurrences of the same argument would return the last match. For
34.321 + * example,
34.322 + * <blockquote><pre>
34.323 + * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
34.324 + * String forParsing = "x, y, z";
34.325 + * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
34.326 + * // result now equals {new String("z")}
34.327 + * </pre></blockquote>
34.328 + *
34.329 + * <h4><a name="synchronization">Synchronization</a></h4>
34.330 + *
34.331 + * <p>
34.332 + * Message formats are not synchronized.
34.333 + * It is recommended to create separate format instances for each thread.
34.334 + * If multiple threads access a format concurrently, it must be synchronized
34.335 + * externally.
34.336 + *
34.337 + * @see java.util.Locale
34.338 + * @see Format
34.339 + * @see NumberFormat
34.340 + * @see DecimalFormat
34.341 + * @see DecimalFormatSymbols
34.342 + * @see ChoiceFormat
34.343 + * @see DateFormat
34.344 + * @see SimpleDateFormat
34.345 + *
34.346 + * @author Mark Davis
34.347 + */
34.348 +
34.349 +public class MessageFormat extends Format {
34.350 +
34.351 + private static final long serialVersionUID = 6479157306784022952L;
34.352 +
34.353 + /**
34.354 + * Constructs a MessageFormat for the default locale and the
34.355 + * specified pattern.
34.356 + * The constructor first sets the locale, then parses the pattern and
34.357 + * creates a list of subformats for the format elements contained in it.
34.358 + * Patterns and their interpretation are specified in the
34.359 + * <a href="#patterns">class description</a>.
34.360 + *
34.361 + * @param pattern the pattern for this message format
34.362 + * @exception IllegalArgumentException if the pattern is invalid
34.363 + */
34.364 + public MessageFormat(String pattern) {
34.365 + this.locale = Locale.getDefault(Locale.Category.FORMAT);
34.366 + applyPattern(pattern);
34.367 + }
34.368 +
34.369 + /**
34.370 + * Constructs a MessageFormat for the specified locale and
34.371 + * pattern.
34.372 + * The constructor first sets the locale, then parses the pattern and
34.373 + * creates a list of subformats for the format elements contained in it.
34.374 + * Patterns and their interpretation are specified in the
34.375 + * <a href="#patterns">class description</a>.
34.376 + *
34.377 + * @param pattern the pattern for this message format
34.378 + * @param locale the locale for this message format
34.379 + * @exception IllegalArgumentException if the pattern is invalid
34.380 + * @since 1.4
34.381 + */
34.382 + public MessageFormat(String pattern, Locale locale) {
34.383 + this.locale = locale;
34.384 + applyPattern(pattern);
34.385 + }
34.386 +
34.387 + /**
34.388 + * Sets the locale to be used when creating or comparing subformats.
34.389 + * This affects subsequent calls
34.390 + * <ul>
34.391 + * <li>to the {@link #applyPattern applyPattern}
34.392 + * and {@link #toPattern toPattern} methods if format elements specify
34.393 + * a format type and therefore have the subformats created in the
34.394 + * <code>applyPattern</code> method, as well as
34.395 + * <li>to the <code>format</code> and
34.396 + * {@link #formatToCharacterIterator formatToCharacterIterator} methods
34.397 + * if format elements do not specify a format type and therefore have
34.398 + * the subformats created in the formatting methods.
34.399 + * </ul>
34.400 + * Subformats that have already been created are not affected.
34.401 + *
34.402 + * @param locale the locale to be used when creating or comparing subformats
34.403 + */
34.404 + public void setLocale(Locale locale) {
34.405 + this.locale = locale;
34.406 + }
34.407 +
34.408 + /**
34.409 + * Gets the locale that's used when creating or comparing subformats.
34.410 + *
34.411 + * @return the locale used when creating or comparing subformats
34.412 + */
34.413 + public Locale getLocale() {
34.414 + return locale;
34.415 + }
34.416 +
34.417 +
34.418 + /**
34.419 + * Sets the pattern used by this message format.
34.420 + * The method parses the pattern and creates a list of subformats
34.421 + * for the format elements contained in it.
34.422 + * Patterns and their interpretation are specified in the
34.423 + * <a href="#patterns">class description</a>.
34.424 + *
34.425 + * @param pattern the pattern for this message format
34.426 + * @exception IllegalArgumentException if the pattern is invalid
34.427 + */
34.428 + public void applyPattern(String pattern) {
34.429 + StringBuilder[] segments = new StringBuilder[4];
34.430 + // Allocate only segments[SEG_RAW] here. The rest are
34.431 + // allocated on demand.
34.432 + segments[SEG_RAW] = new StringBuilder();
34.433 +
34.434 + int part = SEG_RAW;
34.435 + int formatNumber = 0;
34.436 + boolean inQuote = false;
34.437 + int braceStack = 0;
34.438 + maxOffset = -1;
34.439 + for (int i = 0; i < pattern.length(); ++i) {
34.440 + char ch = pattern.charAt(i);
34.441 + if (part == SEG_RAW) {
34.442 + if (ch == '\'') {
34.443 + if (i + 1 < pattern.length()
34.444 + && pattern.charAt(i+1) == '\'') {
34.445 + segments[part].append(ch); // handle doubles
34.446 + ++i;
34.447 + } else {
34.448 + inQuote = !inQuote;
34.449 + }
34.450 + } else if (ch == '{' && !inQuote) {
34.451 + part = SEG_INDEX;
34.452 + if (segments[SEG_INDEX] == null) {
34.453 + segments[SEG_INDEX] = new StringBuilder();
34.454 + }
34.455 + } else {
34.456 + segments[part].append(ch);
34.457 + }
34.458 + } else {
34.459 + if (inQuote) { // just copy quotes in parts
34.460 + segments[part].append(ch);
34.461 + if (ch == '\'') {
34.462 + inQuote = false;
34.463 + }
34.464 + } else {
34.465 + switch (ch) {
34.466 + case ',':
34.467 + if (part < SEG_MODIFIER) {
34.468 + if (segments[++part] == null) {
34.469 + segments[part] = new StringBuilder();
34.470 + }
34.471 + } else {
34.472 + segments[part].append(ch);
34.473 + }
34.474 + break;
34.475 + case '{':
34.476 + ++braceStack;
34.477 + segments[part].append(ch);
34.478 + break;
34.479 + case '}':
34.480 + if (braceStack == 0) {
34.481 + part = SEG_RAW;
34.482 + makeFormat(i, formatNumber, segments);
34.483 + formatNumber++;
34.484 + // throw away other segments
34.485 + segments[SEG_INDEX] = null;
34.486 + segments[SEG_TYPE] = null;
34.487 + segments[SEG_MODIFIER] = null;
34.488 + } else {
34.489 + --braceStack;
34.490 + segments[part].append(ch);
34.491 + }
34.492 + break;
34.493 + case ' ':
34.494 + // Skip any leading space chars for SEG_TYPE.
34.495 + if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
34.496 + segments[part].append(ch);
34.497 + }
34.498 + break;
34.499 + case '\'':
34.500 + inQuote = true;
34.501 + // fall through, so we keep quotes in other parts
34.502 + default:
34.503 + segments[part].append(ch);
34.504 + break;
34.505 + }
34.506 + }
34.507 + }
34.508 + }
34.509 + if (braceStack == 0 && part != 0) {
34.510 + maxOffset = -1;
34.511 + throw new IllegalArgumentException("Unmatched braces in the pattern.");
34.512 + }
34.513 + this.pattern = segments[0].toString();
34.514 + }
34.515 +
34.516 +
34.517 + /**
34.518 + * Returns a pattern representing the current state of the message format.
34.519 + * The string is constructed from internal information and therefore
34.520 + * does not necessarily equal the previously applied pattern.
34.521 + *
34.522 + * @return a pattern representing the current state of the message format
34.523 + */
34.524 + public String toPattern() {
34.525 + // later, make this more extensible
34.526 + int lastOffset = 0;
34.527 + StringBuilder result = new StringBuilder();
34.528 + for (int i = 0; i <= maxOffset; ++i) {
34.529 + copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
34.530 + lastOffset = offsets[i];
34.531 + result.append('{').append(argumentNumbers[i]);
34.532 + Format fmt = formats[i];
34.533 + if (fmt == null) {
34.534 + // do nothing, string format
34.535 + } else if (fmt instanceof NumberFormat) {
34.536 + if (fmt.equals(NumberFormat.getInstance(locale))) {
34.537 + result.append(",number");
34.538 + } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
34.539 + result.append(",number,currency");
34.540 + } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
34.541 + result.append(",number,percent");
34.542 + } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
34.543 + result.append(",number,integer");
34.544 + } else {
34.545 + if (fmt instanceof DecimalFormat) {
34.546 + result.append(",number,").append(((DecimalFormat)fmt).toPattern());
34.547 + } else if (fmt instanceof ChoiceFormat) {
34.548 + result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
34.549 + } else {
34.550 + // UNKNOWN
34.551 + }
34.552 + }
34.553 + } else if (fmt instanceof DateFormat) {
34.554 + int index;
34.555 + for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
34.556 + DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
34.557 + locale);
34.558 + if (fmt.equals(df)) {
34.559 + result.append(",date");
34.560 + break;
34.561 + }
34.562 + df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
34.563 + locale);
34.564 + if (fmt.equals(df)) {
34.565 + result.append(",time");
34.566 + break;
34.567 + }
34.568 + }
34.569 + if (index >= DATE_TIME_MODIFIERS.length) {
34.570 + if (fmt instanceof SimpleDateFormat) {
34.571 + result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
34.572 + } else {
34.573 + // UNKNOWN
34.574 + }
34.575 + } else if (index != MODIFIER_DEFAULT) {
34.576 + result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
34.577 + }
34.578 + } else {
34.579 + //result.append(", unknown");
34.580 + }
34.581 + result.append('}');
34.582 + }
34.583 + copyAndFixQuotes(pattern, lastOffset, pattern.length(), result);
34.584 + return result.toString();
34.585 + }
34.586 +
34.587 + /**
34.588 + * Sets the formats to use for the values passed into
34.589 + * <code>format</code> methods or returned from <code>parse</code>
34.590 + * methods. The indices of elements in <code>newFormats</code>
34.591 + * correspond to the argument indices used in the previously set
34.592 + * pattern string.
34.593 + * The order of formats in <code>newFormats</code> thus corresponds to
34.594 + * the order of elements in the <code>arguments</code> array passed
34.595 + * to the <code>format</code> methods or the result array returned
34.596 + * by the <code>parse</code> methods.
34.597 + * <p>
34.598 + * If an argument index is used for more than one format element
34.599 + * in the pattern string, then the corresponding new format is used
34.600 + * for all such format elements. If an argument index is not used
34.601 + * for any format element in the pattern string, then the
34.602 + * corresponding new format is ignored. If fewer formats are provided
34.603 + * than needed, then only the formats for argument indices less
34.604 + * than <code>newFormats.length</code> are replaced.
34.605 + *
34.606 + * @param newFormats the new formats to use
34.607 + * @exception NullPointerException if <code>newFormats</code> is null
34.608 + * @since 1.4
34.609 + */
34.610 + public void setFormatsByArgumentIndex(Format[] newFormats) {
34.611 + for (int i = 0; i <= maxOffset; i++) {
34.612 + int j = argumentNumbers[i];
34.613 + if (j < newFormats.length) {
34.614 + formats[i] = newFormats[j];
34.615 + }
34.616 + }
34.617 + }
34.618 +
34.619 + /**
34.620 + * Sets the formats to use for the format elements in the
34.621 + * previously set pattern string.
34.622 + * The order of formats in <code>newFormats</code> corresponds to
34.623 + * the order of format elements in the pattern string.
34.624 + * <p>
34.625 + * If more formats are provided than needed by the pattern string,
34.626 + * the remaining ones are ignored. If fewer formats are provided
34.627 + * than needed, then only the first <code>newFormats.length</code>
34.628 + * formats are replaced.
34.629 + * <p>
34.630 + * Since the order of format elements in a pattern string often
34.631 + * changes during localization, it is generally better to use the
34.632 + * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
34.633 + * method, which assumes an order of formats corresponding to the
34.634 + * order of elements in the <code>arguments</code> array passed to
34.635 + * the <code>format</code> methods or the result array returned by
34.636 + * the <code>parse</code> methods.
34.637 + *
34.638 + * @param newFormats the new formats to use
34.639 + * @exception NullPointerException if <code>newFormats</code> is null
34.640 + */
34.641 + public void setFormats(Format[] newFormats) {
34.642 + int runsToCopy = newFormats.length;
34.643 + if (runsToCopy > maxOffset + 1) {
34.644 + runsToCopy = maxOffset + 1;
34.645 + }
34.646 + for (int i = 0; i < runsToCopy; i++) {
34.647 + formats[i] = newFormats[i];
34.648 + }
34.649 + }
34.650 +
34.651 + /**
34.652 + * Sets the format to use for the format elements within the
34.653 + * previously set pattern string that use the given argument
34.654 + * index.
34.655 + * The argument index is part of the format element definition and
34.656 + * represents an index into the <code>arguments</code> array passed
34.657 + * to the <code>format</code> methods or the result array returned
34.658 + * by the <code>parse</code> methods.
34.659 + * <p>
34.660 + * If the argument index is used for more than one format element
34.661 + * in the pattern string, then the new format is used for all such
34.662 + * format elements. If the argument index is not used for any format
34.663 + * element in the pattern string, then the new format is ignored.
34.664 + *
34.665 + * @param argumentIndex the argument index for which to use the new format
34.666 + * @param newFormat the new format to use
34.667 + * @since 1.4
34.668 + */
34.669 + public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
34.670 + for (int j = 0; j <= maxOffset; j++) {
34.671 + if (argumentNumbers[j] == argumentIndex) {
34.672 + formats[j] = newFormat;
34.673 + }
34.674 + }
34.675 + }
34.676 +
34.677 + /**
34.678 + * Sets the format to use for the format element with the given
34.679 + * format element index within the previously set pattern string.
34.680 + * The format element index is the zero-based number of the format
34.681 + * element counting from the start of the pattern string.
34.682 + * <p>
34.683 + * Since the order of format elements in a pattern string often
34.684 + * changes during localization, it is generally better to use the
34.685 + * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
34.686 + * method, which accesses format elements based on the argument
34.687 + * index they specify.
34.688 + *
34.689 + * @param formatElementIndex the index of a format element within the pattern
34.690 + * @param newFormat the format to use for the specified format element
34.691 + * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
34.692 + * larger than the number of format elements in the pattern string
34.693 + */
34.694 + public void setFormat(int formatElementIndex, Format newFormat) {
34.695 + formats[formatElementIndex] = newFormat;
34.696 + }
34.697 +
34.698 + /**
34.699 + * Gets the formats used for the values passed into
34.700 + * <code>format</code> methods or returned from <code>parse</code>
34.701 + * methods. The indices of elements in the returned array
34.702 + * correspond to the argument indices used in the previously set
34.703 + * pattern string.
34.704 + * The order of formats in the returned array thus corresponds to
34.705 + * the order of elements in the <code>arguments</code> array passed
34.706 + * to the <code>format</code> methods or the result array returned
34.707 + * by the <code>parse</code> methods.
34.708 + * <p>
34.709 + * If an argument index is used for more than one format element
34.710 + * in the pattern string, then the format used for the last such
34.711 + * format element is returned in the array. If an argument index
34.712 + * is not used for any format element in the pattern string, then
34.713 + * null is returned in the array.
34.714 + *
34.715 + * @return the formats used for the arguments within the pattern
34.716 + * @since 1.4
34.717 + */
34.718 + public Format[] getFormatsByArgumentIndex() {
34.719 + int maximumArgumentNumber = -1;
34.720 + for (int i = 0; i <= maxOffset; i++) {
34.721 + if (argumentNumbers[i] > maximumArgumentNumber) {
34.722 + maximumArgumentNumber = argumentNumbers[i];
34.723 + }
34.724 + }
34.725 + Format[] resultArray = new Format[maximumArgumentNumber + 1];
34.726 + for (int i = 0; i <= maxOffset; i++) {
34.727 + resultArray[argumentNumbers[i]] = formats[i];
34.728 + }
34.729 + return resultArray;
34.730 + }
34.731 +
34.732 + /**
34.733 + * Gets the formats used for the format elements in the
34.734 + * previously set pattern string.
34.735 + * The order of formats in the returned array corresponds to
34.736 + * the order of format elements in the pattern string.
34.737 + * <p>
34.738 + * Since the order of format elements in a pattern string often
34.739 + * changes during localization, it's generally better to use the
34.740 + * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
34.741 + * method, which assumes an order of formats corresponding to the
34.742 + * order of elements in the <code>arguments</code> array passed to
34.743 + * the <code>format</code> methods or the result array returned by
34.744 + * the <code>parse</code> methods.
34.745 + *
34.746 + * @return the formats used for the format elements in the pattern
34.747 + */
34.748 + public Format[] getFormats() {
34.749 + Format[] resultArray = new Format[maxOffset + 1];
34.750 + System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1);
34.751 + return resultArray;
34.752 + }
34.753 +
34.754 + /**
34.755 + * Formats an array of objects and appends the <code>MessageFormat</code>'s
34.756 + * pattern, with format elements replaced by the formatted objects, to the
34.757 + * provided <code>StringBuffer</code>.
34.758 + * <p>
34.759 + * The text substituted for the individual format elements is derived from
34.760 + * the current subformat of the format element and the
34.761 + * <code>arguments</code> element at the format element's argument index
34.762 + * as indicated by the first matching line of the following table. An
34.763 + * argument is <i>unavailable</i> if <code>arguments</code> is
34.764 + * <code>null</code> or has fewer than argumentIndex+1 elements.
34.765 + * <p>
34.766 + * <table border=1 summary="Examples of subformat,argument,and formatted text">
34.767 + * <tr>
34.768 + * <th>Subformat
34.769 + * <th>Argument
34.770 + * <th>Formatted Text
34.771 + * <tr>
34.772 + * <td><i>any</i>
34.773 + * <td><i>unavailable</i>
34.774 + * <td><code>"{" + argumentIndex + "}"</code>
34.775 + * <tr>
34.776 + * <td><i>any</i>
34.777 + * <td><code>null</code>
34.778 + * <td><code>"null"</code>
34.779 + * <tr>
34.780 + * <td><code>instanceof ChoiceFormat</code>
34.781 + * <td><i>any</i>
34.782 + * <td><code>subformat.format(argument).indexOf('{') >= 0 ?<br>
34.783 + * (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
34.784 + * subformat.format(argument)</code>
34.785 + * <tr>
34.786 + * <td><code>!= null</code>
34.787 + * <td><i>any</i>
34.788 + * <td><code>subformat.format(argument)</code>
34.789 + * <tr>
34.790 + * <td><code>null</code>
34.791 + * <td><code>instanceof Number</code>
34.792 + * <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
34.793 + * <tr>
34.794 + * <td><code>null</code>
34.795 + * <td><code>instanceof Date</code>
34.796 + * <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
34.797 + * <tr>
34.798 + * <td><code>null</code>
34.799 + * <td><code>instanceof String</code>
34.800 + * <td><code>argument</code>
34.801 + * <tr>
34.802 + * <td><code>null</code>
34.803 + * <td><i>any</i>
34.804 + * <td><code>argument.toString()</code>
34.805 + * </table>
34.806 + * <p>
34.807 + * If <code>pos</code> is non-null, and refers to
34.808 + * <code>Field.ARGUMENT</code>, the location of the first formatted
34.809 + * string will be returned.
34.810 + *
34.811 + * @param arguments an array of objects to be formatted and substituted.
34.812 + * @param result where text is appended.
34.813 + * @param pos On input: an alignment field, if desired.
34.814 + * On output: the offsets of the alignment field.
34.815 + * @exception IllegalArgumentException if an argument in the
34.816 + * <code>arguments</code> array is not of the type
34.817 + * expected by the format element(s) that use it.
34.818 + */
34.819 + public final StringBuffer format(Object[] arguments, StringBuffer result,
34.820 + FieldPosition pos)
34.821 + {
34.822 + return subformat(arguments, result, pos, null);
34.823 + }
34.824 +
34.825 + /**
34.826 + * Creates a MessageFormat with the given pattern and uses it
34.827 + * to format the given arguments. This is equivalent to
34.828 + * <blockquote>
34.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>
34.830 + * </blockquote>
34.831 + *
34.832 + * @exception IllegalArgumentException if the pattern is invalid,
34.833 + * or if an argument in the <code>arguments</code> array
34.834 + * is not of the type expected by the format element(s)
34.835 + * that use it.
34.836 + */
34.837 + public static String format(String pattern, Object ... arguments) {
34.838 + MessageFormat temp = new MessageFormat(pattern);
34.839 + return temp.format(arguments);
34.840 + }
34.841 +
34.842 + // Overrides
34.843 + /**
34.844 + * Formats an array of objects and appends the <code>MessageFormat</code>'s
34.845 + * pattern, with format elements replaced by the formatted objects, to the
34.846 + * provided <code>StringBuffer</code>.
34.847 + * This is equivalent to
34.848 + * <blockquote>
34.849 + * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
34.850 + * </blockquote>
34.851 + *
34.852 + * @param arguments an array of objects to be formatted and substituted.
34.853 + * @param result where text is appended.
34.854 + * @param pos On input: an alignment field, if desired.
34.855 + * On output: the offsets of the alignment field.
34.856 + * @exception IllegalArgumentException if an argument in the
34.857 + * <code>arguments</code> array is not of the type
34.858 + * expected by the format element(s) that use it.
34.859 + */
34.860 + public final StringBuffer format(Object arguments, StringBuffer result,
34.861 + FieldPosition pos)
34.862 + {
34.863 + return subformat((Object[]) arguments, result, pos, null);
34.864 + }
34.865 +
34.866 + /**
34.867 + * Formats an array of objects and inserts them into the
34.868 + * <code>MessageFormat</code>'s pattern, producing an
34.869 + * <code>AttributedCharacterIterator</code>.
34.870 + * You can use the returned <code>AttributedCharacterIterator</code>
34.871 + * to build the resulting String, as well as to determine information
34.872 + * about the resulting String.
34.873 + * <p>
34.874 + * The text of the returned <code>AttributedCharacterIterator</code> is
34.875 + * the same that would be returned by
34.876 + * <blockquote>
34.877 + * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
34.878 + * </blockquote>
34.879 + * <p>
34.880 + * In addition, the <code>AttributedCharacterIterator</code> contains at
34.881 + * least attributes indicating where text was generated from an
34.882 + * argument in the <code>arguments</code> array. The keys of these attributes are of
34.883 + * type <code>MessageFormat.Field</code>, their values are
34.884 + * <code>Integer</code> objects indicating the index in the <code>arguments</code>
34.885 + * array of the argument from which the text was generated.
34.886 + * <p>
34.887 + * The attributes/value from the underlying <code>Format</code>
34.888 + * instances that <code>MessageFormat</code> uses will also be
34.889 + * placed in the resulting <code>AttributedCharacterIterator</code>.
34.890 + * This allows you to not only find where an argument is placed in the
34.891 + * resulting String, but also which fields it contains in turn.
34.892 + *
34.893 + * @param arguments an array of objects to be formatted and substituted.
34.894 + * @return AttributedCharacterIterator describing the formatted value.
34.895 + * @exception NullPointerException if <code>arguments</code> is null.
34.896 + * @exception IllegalArgumentException if an argument in the
34.897 + * <code>arguments</code> array is not of the type
34.898 + * expected by the format element(s) that use it.
34.899 + * @since 1.4
34.900 + */
34.901 + public AttributedCharacterIterator formatToCharacterIterator(Object arguments) {
34.902 + StringBuffer result = new StringBuffer();
34.903 + ArrayList iterators = new ArrayList();
34.904 +
34.905 + if (arguments == null) {
34.906 + throw new NullPointerException(
34.907 + "formatToCharacterIterator must be passed non-null object");
34.908 + }
34.909 + subformat((Object[]) arguments, result, null, iterators);
34.910 + if (iterators.size() == 0) {
34.911 + return createAttributedCharacterIterator("");
34.912 + }
34.913 + return createAttributedCharacterIterator(
34.914 + (AttributedCharacterIterator[])iterators.toArray(
34.915 + new AttributedCharacterIterator[iterators.size()]));
34.916 + }
34.917 +
34.918 + /**
34.919 + * Parses the string.
34.920 + *
34.921 + * <p>Caveats: The parse may fail in a number of circumstances.
34.922 + * For example:
34.923 + * <ul>
34.924 + * <li>If one of the arguments does not occur in the pattern.
34.925 + * <li>If the format of an argument loses information, such as
34.926 + * with a choice format where a large number formats to "many".
34.927 + * <li>Does not yet handle recursion (where
34.928 + * the substituted strings contain {n} references.)
34.929 + * <li>Will not always find a match (or the correct match)
34.930 + * if some part of the parse is ambiguous.
34.931 + * For example, if the pattern "{1},{2}" is used with the
34.932 + * string arguments {"a,b", "c"}, it will format as "a,b,c".
34.933 + * When the result is parsed, it will return {"a", "b,c"}.
34.934 + * <li>If a single argument is parsed more than once in the string,
34.935 + * then the later parse wins.
34.936 + * </ul>
34.937 + * When the parse fails, use ParsePosition.getErrorIndex() to find out
34.938 + * where in the string the parsing failed. The returned error
34.939 + * index is the starting offset of the sub-patterns that the string
34.940 + * is comparing with. For example, if the parsing string "AAA {0} BBB"
34.941 + * is comparing against the pattern "AAD {0} BBB", the error index is
34.942 + * 0. When an error occurs, the call to this method will return null.
34.943 + * If the source is null, return an empty array.
34.944 + */
34.945 + public Object[] parse(String source, ParsePosition pos) {
34.946 + if (source == null) {
34.947 + Object[] empty = {};
34.948 + return empty;
34.949 + }
34.950 +
34.951 + int maximumArgumentNumber = -1;
34.952 + for (int i = 0; i <= maxOffset; i++) {
34.953 + if (argumentNumbers[i] > maximumArgumentNumber) {
34.954 + maximumArgumentNumber = argumentNumbers[i];
34.955 + }
34.956 + }
34.957 + Object[] resultArray = new Object[maximumArgumentNumber + 1];
34.958 +
34.959 + int patternOffset = 0;
34.960 + int sourceOffset = pos.index;
34.961 + ParsePosition tempStatus = new ParsePosition(0);
34.962 + for (int i = 0; i <= maxOffset; ++i) {
34.963 + // match up to format
34.964 + int len = offsets[i] - patternOffset;
34.965 + if (len == 0 || pattern.regionMatches(patternOffset,
34.966 + source, sourceOffset, len)) {
34.967 + sourceOffset += len;
34.968 + patternOffset += len;
34.969 + } else {
34.970 + pos.errorIndex = sourceOffset;
34.971 + return null; // leave index as is to signal error
34.972 + }
34.973 +
34.974 + // now use format
34.975 + if (formats[i] == null) { // string format
34.976 + // if at end, use longest possible match
34.977 + // otherwise uses first match to intervening string
34.978 + // does NOT recursively try all possibilities
34.979 + int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length();
34.980 +
34.981 + int next;
34.982 + if (patternOffset >= tempLength) {
34.983 + next = source.length();
34.984 + }else{
34.985 + next = source.indexOf(pattern.substring(patternOffset, tempLength),
34.986 + sourceOffset);
34.987 + }
34.988 +
34.989 + if (next < 0) {
34.990 + pos.errorIndex = sourceOffset;
34.991 + return null; // leave index as is to signal error
34.992 + } else {
34.993 + String strValue= source.substring(sourceOffset,next);
34.994 + if (!strValue.equals("{"+argumentNumbers[i]+"}"))
34.995 + resultArray[argumentNumbers[i]]
34.996 + = source.substring(sourceOffset,next);
34.997 + sourceOffset = next;
34.998 + }
34.999 + } else {
34.1000 + tempStatus.index = sourceOffset;
34.1001 + resultArray[argumentNumbers[i]]
34.1002 + = formats[i].parseObject(source,tempStatus);
34.1003 + if (tempStatus.index == sourceOffset) {
34.1004 + pos.errorIndex = sourceOffset;
34.1005 + return null; // leave index as is to signal error
34.1006 + }
34.1007 + sourceOffset = tempStatus.index; // update
34.1008 + }
34.1009 + }
34.1010 + int len = pattern.length() - patternOffset;
34.1011 + if (len == 0 || pattern.regionMatches(patternOffset,
34.1012 + source, sourceOffset, len)) {
34.1013 + pos.index = sourceOffset + len;
34.1014 + } else {
34.1015 + pos.errorIndex = sourceOffset;
34.1016 + return null; // leave index as is to signal error
34.1017 + }
34.1018 + return resultArray;
34.1019 + }
34.1020 +
34.1021 + /**
34.1022 + * Parses text from the beginning of the given string to produce an object
34.1023 + * array.
34.1024 + * The method may not use the entire text of the given string.
34.1025 + * <p>
34.1026 + * See the {@link #parse(String, ParsePosition)} method for more information
34.1027 + * on message parsing.
34.1028 + *
34.1029 + * @param source A <code>String</code> whose beginning should be parsed.
34.1030 + * @return An <code>Object</code> array parsed from the string.
34.1031 + * @exception ParseException if the beginning of the specified string
34.1032 + * cannot be parsed.
34.1033 + */
34.1034 + public Object[] parse(String source) throws ParseException {
34.1035 + ParsePosition pos = new ParsePosition(0);
34.1036 + Object[] result = parse(source, pos);
34.1037 + if (pos.index == 0) // unchanged, returned object is null
34.1038 + throw new ParseException("MessageFormat parse error!", pos.errorIndex);
34.1039 +
34.1040 + return result;
34.1041 + }
34.1042 +
34.1043 + /**
34.1044 + * Parses text from a string to produce an object array.
34.1045 + * <p>
34.1046 + * The method attempts to parse text starting at the index given by
34.1047 + * <code>pos</code>.
34.1048 + * If parsing succeeds, then the index of <code>pos</code> is updated
34.1049 + * to the index after the last character used (parsing does not necessarily
34.1050 + * use all characters up to the end of the string), and the parsed
34.1051 + * object array is returned. The updated <code>pos</code> can be used to
34.1052 + * indicate the starting point for the next call to this method.
34.1053 + * If an error occurs, then the index of <code>pos</code> is not
34.1054 + * changed, the error index of <code>pos</code> is set to the index of
34.1055 + * the character where the error occurred, and null is returned.
34.1056 + * <p>
34.1057 + * See the {@link #parse(String, ParsePosition)} method for more information
34.1058 + * on message parsing.
34.1059 + *
34.1060 + * @param source A <code>String</code>, part of which should be parsed.
34.1061 + * @param pos A <code>ParsePosition</code> object with index and error
34.1062 + * index information as described above.
34.1063 + * @return An <code>Object</code> array parsed from the string. In case of
34.1064 + * error, returns null.
34.1065 + * @exception NullPointerException if <code>pos</code> is null.
34.1066 + */
34.1067 + public Object parseObject(String source, ParsePosition pos) {
34.1068 + return parse(source, pos);
34.1069 + }
34.1070 +
34.1071 + /**
34.1072 + * Creates and returns a copy of this object.
34.1073 + *
34.1074 + * @return a clone of this instance.
34.1075 + */
34.1076 + public Object clone() {
34.1077 + MessageFormat other = (MessageFormat) super.clone();
34.1078 +
34.1079 + // clone arrays. Can't do with utility because of bug in Cloneable
34.1080 + other.formats = (Format[]) formats.clone(); // shallow clone
34.1081 + for (int i = 0; i < formats.length; ++i) {
34.1082 + if (formats[i] != null)
34.1083 + other.formats[i] = (Format)formats[i].clone();
34.1084 + }
34.1085 + // for primitives or immutables, shallow clone is enough
34.1086 + other.offsets = (int[]) offsets.clone();
34.1087 + other.argumentNumbers = (int[]) argumentNumbers.clone();
34.1088 +
34.1089 + return other;
34.1090 + }
34.1091 +
34.1092 + /**
34.1093 + * Equality comparison between two message format objects
34.1094 + */
34.1095 + public boolean equals(Object obj) {
34.1096 + if (this == obj) // quick check
34.1097 + return true;
34.1098 + if (obj == null || getClass() != obj.getClass())
34.1099 + return false;
34.1100 + MessageFormat other = (MessageFormat) obj;
34.1101 + return (maxOffset == other.maxOffset
34.1102 + && pattern.equals(other.pattern)
34.1103 + && ((locale != null && locale.equals(other.locale))
34.1104 + || (locale == null && other.locale == null))
34.1105 + && Arrays.equals(offsets,other.offsets)
34.1106 + && Arrays.equals(argumentNumbers,other.argumentNumbers)
34.1107 + && Arrays.equals(formats,other.formats));
34.1108 + }
34.1109 +
34.1110 + /**
34.1111 + * Generates a hash code for the message format object.
34.1112 + */
34.1113 + public int hashCode() {
34.1114 + return pattern.hashCode(); // enough for reasonable distribution
34.1115 + }
34.1116 +
34.1117 +
34.1118 + /**
34.1119 + * Defines constants that are used as attribute keys in the
34.1120 + * <code>AttributedCharacterIterator</code> returned
34.1121 + * from <code>MessageFormat.formatToCharacterIterator</code>.
34.1122 + *
34.1123 + * @since 1.4
34.1124 + */
34.1125 + public static class Field extends Format.Field {
34.1126 +
34.1127 + // Proclaim serial compatibility with 1.4 FCS
34.1128 + private static final long serialVersionUID = 7899943957617360810L;
34.1129 +
34.1130 + /**
34.1131 + * Creates a Field with the specified name.
34.1132 + *
34.1133 + * @param name Name of the attribute
34.1134 + */
34.1135 + protected Field(String name) {
34.1136 + super(name);
34.1137 + }
34.1138 +
34.1139 + /**
34.1140 + * Resolves instances being deserialized to the predefined constants.
34.1141 + *
34.1142 + * @throws InvalidObjectException if the constant could not be
34.1143 + * resolved.
34.1144 + * @return resolved MessageFormat.Field constant
34.1145 + */
34.1146 + protected Object readResolve() throws InvalidObjectException {
34.1147 + if (this.getClass() != MessageFormat.Field.class) {
34.1148 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
34.1149 + }
34.1150 +
34.1151 + return ARGUMENT;
34.1152 + }
34.1153 +
34.1154 + //
34.1155 + // The constants
34.1156 + //
34.1157 +
34.1158 + /**
34.1159 + * Constant identifying a portion of a message that was generated
34.1160 + * from an argument passed into <code>formatToCharacterIterator</code>.
34.1161 + * The value associated with the key will be an <code>Integer</code>
34.1162 + * indicating the index in the <code>arguments</code> array of the
34.1163 + * argument from which the text was generated.
34.1164 + */
34.1165 + public final static Field ARGUMENT =
34.1166 + new Field("message argument field");
34.1167 + }
34.1168 +
34.1169 + // ===========================privates============================
34.1170 +
34.1171 + /**
34.1172 + * The locale to use for formatting numbers and dates.
34.1173 + * @serial
34.1174 + */
34.1175 + private Locale locale;
34.1176 +
34.1177 + /**
34.1178 + * The string that the formatted values are to be plugged into. In other words, this
34.1179 + * is the pattern supplied on construction with all of the {} expressions taken out.
34.1180 + * @serial
34.1181 + */
34.1182 + private String pattern = "";
34.1183 +
34.1184 + /** The initially expected number of subformats in the format */
34.1185 + private static final int INITIAL_FORMATS = 10;
34.1186 +
34.1187 + /**
34.1188 + * An array of formatters, which are used to format the arguments.
34.1189 + * @serial
34.1190 + */
34.1191 + private Format[] formats = new Format[INITIAL_FORMATS];
34.1192 +
34.1193 + /**
34.1194 + * The positions where the results of formatting each argument are to be inserted
34.1195 + * into the pattern.
34.1196 + * @serial
34.1197 + */
34.1198 + private int[] offsets = new int[INITIAL_FORMATS];
34.1199 +
34.1200 + /**
34.1201 + * The argument numbers corresponding to each formatter. (The formatters are stored
34.1202 + * in the order they occur in the pattern, not in the order in which the arguments
34.1203 + * are specified.)
34.1204 + * @serial
34.1205 + */
34.1206 + private int[] argumentNumbers = new int[INITIAL_FORMATS];
34.1207 +
34.1208 + /**
34.1209 + * One less than the number of entries in <code>offsets</code>. Can also be thought of
34.1210 + * as the index of the highest-numbered element in <code>offsets</code> that is being used.
34.1211 + * All of these arrays should have the same number of elements being used as <code>offsets</code>
34.1212 + * does, and so this variable suffices to tell us how many entries are in all of them.
34.1213 + * @serial
34.1214 + */
34.1215 + private int maxOffset = -1;
34.1216 +
34.1217 + /**
34.1218 + * Internal routine used by format. If <code>characterIterators</code> is
34.1219 + * non-null, AttributedCharacterIterator will be created from the
34.1220 + * subformats as necessary. If <code>characterIterators</code> is null
34.1221 + * and <code>fp</code> is non-null and identifies
34.1222 + * <code>Field.MESSAGE_ARGUMENT</code>, the location of
34.1223 + * the first replaced argument will be set in it.
34.1224 + *
34.1225 + * @exception IllegalArgumentException if an argument in the
34.1226 + * <code>arguments</code> array is not of the type
34.1227 + * expected by the format element(s) that use it.
34.1228 + */
34.1229 + private StringBuffer subformat(Object[] arguments, StringBuffer result,
34.1230 + FieldPosition fp, List characterIterators) {
34.1231 + // note: this implementation assumes a fast substring & index.
34.1232 + // if this is not true, would be better to append chars one by one.
34.1233 + int lastOffset = 0;
34.1234 + int last = result.length();
34.1235 + for (int i = 0; i <= maxOffset; ++i) {
34.1236 + result.append(pattern.substring(lastOffset, offsets[i]));
34.1237 + lastOffset = offsets[i];
34.1238 + int argumentNumber = argumentNumbers[i];
34.1239 + if (arguments == null || argumentNumber >= arguments.length) {
34.1240 + result.append('{').append(argumentNumber).append('}');
34.1241 + continue;
34.1242 + }
34.1243 + // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
34.1244 + if (false) { // if (argRecursion == 3){
34.1245 + // prevent loop!!!
34.1246 + result.append('\uFFFD');
34.1247 + } else {
34.1248 + Object obj = arguments[argumentNumber];
34.1249 + String arg = null;
34.1250 + Format subFormatter = null;
34.1251 + if (obj == null) {
34.1252 + arg = "null";
34.1253 + } else if (formats[i] != null) {
34.1254 + subFormatter = formats[i];
34.1255 + if (subFormatter instanceof ChoiceFormat) {
34.1256 + arg = formats[i].format(obj);
34.1257 + if (arg.indexOf('{') >= 0) {
34.1258 + subFormatter = new MessageFormat(arg, locale);
34.1259 + obj = arguments;
34.1260 + arg = null;
34.1261 + }
34.1262 + }
34.1263 + } else if (obj instanceof Number) {
34.1264 + // format number if can
34.1265 + subFormatter = NumberFormat.getInstance(locale);
34.1266 + } else if (obj instanceof Date) {
34.1267 + // format a Date if can
34.1268 + subFormatter = DateFormat.getDateTimeInstance(
34.1269 + DateFormat.SHORT, DateFormat.SHORT, locale);//fix
34.1270 + } else if (obj instanceof String) {
34.1271 + arg = (String) obj;
34.1272 +
34.1273 + } else {
34.1274 + arg = obj.toString();
34.1275 + if (arg == null) arg = "null";
34.1276 + }
34.1277 +
34.1278 + // At this point we are in two states, either subFormatter
34.1279 + // is non-null indicating we should format obj using it,
34.1280 + // or arg is non-null and we should use it as the value.
34.1281 +
34.1282 + if (characterIterators != null) {
34.1283 + // If characterIterators is non-null, it indicates we need
34.1284 + // to get the CharacterIterator from the child formatter.
34.1285 + if (last != result.length()) {
34.1286 + characterIterators.add(
34.1287 + createAttributedCharacterIterator(result.substring
34.1288 + (last)));
34.1289 + last = result.length();
34.1290 + }
34.1291 + if (subFormatter != null) {
34.1292 + AttributedCharacterIterator subIterator =
34.1293 + subFormatter.formatToCharacterIterator(obj);
34.1294 +
34.1295 + append(result, subIterator);
34.1296 + if (last != result.length()) {
34.1297 + characterIterators.add(
34.1298 + createAttributedCharacterIterator(
34.1299 + subIterator, Field.ARGUMENT,
34.1300 + Integer.valueOf(argumentNumber)));
34.1301 + last = result.length();
34.1302 + }
34.1303 + arg = null;
34.1304 + }
34.1305 + if (arg != null && arg.length() > 0) {
34.1306 + result.append(arg);
34.1307 + characterIterators.add(
34.1308 + createAttributedCharacterIterator(
34.1309 + arg, Field.ARGUMENT,
34.1310 + Integer.valueOf(argumentNumber)));
34.1311 + last = result.length();
34.1312 + }
34.1313 + }
34.1314 + else {
34.1315 + if (subFormatter != null) {
34.1316 + arg = subFormatter.format(obj);
34.1317 + }
34.1318 + last = result.length();
34.1319 + result.append(arg);
34.1320 + if (i == 0 && fp != null && Field.ARGUMENT.equals(
34.1321 + fp.getFieldAttribute())) {
34.1322 + fp.setBeginIndex(last);
34.1323 + fp.setEndIndex(result.length());
34.1324 + }
34.1325 + last = result.length();
34.1326 + }
34.1327 + }
34.1328 + }
34.1329 + result.append(pattern.substring(lastOffset, pattern.length()));
34.1330 + if (characterIterators != null && last != result.length()) {
34.1331 + characterIterators.add(createAttributedCharacterIterator(
34.1332 + result.substring(last)));
34.1333 + }
34.1334 + return result;
34.1335 + }
34.1336 +
34.1337 + /**
34.1338 + * Convenience method to append all the characters in
34.1339 + * <code>iterator</code> to the StringBuffer <code>result</code>.
34.1340 + */
34.1341 + private void append(StringBuffer result, CharacterIterator iterator) {
34.1342 + if (iterator.first() != CharacterIterator.DONE) {
34.1343 + char aChar;
34.1344 +
34.1345 + result.append(iterator.first());
34.1346 + while ((aChar = iterator.next()) != CharacterIterator.DONE) {
34.1347 + result.append(aChar);
34.1348 + }
34.1349 + }
34.1350 + }
34.1351 +
34.1352 + // Indices for segments
34.1353 + private static final int SEG_RAW = 0;
34.1354 + private static final int SEG_INDEX = 1;
34.1355 + private static final int SEG_TYPE = 2;
34.1356 + private static final int SEG_MODIFIER = 3; // modifier or subformat
34.1357 +
34.1358 + // Indices for type keywords
34.1359 + private static final int TYPE_NULL = 0;
34.1360 + private static final int TYPE_NUMBER = 1;
34.1361 + private static final int TYPE_DATE = 2;
34.1362 + private static final int TYPE_TIME = 3;
34.1363 + private static final int TYPE_CHOICE = 4;
34.1364 +
34.1365 + private static final String[] TYPE_KEYWORDS = {
34.1366 + "",
34.1367 + "number",
34.1368 + "date",
34.1369 + "time",
34.1370 + "choice"
34.1371 + };
34.1372 +
34.1373 + // Indices for number modifiers
34.1374 + private static final int MODIFIER_DEFAULT = 0; // common in number and date-time
34.1375 + private static final int MODIFIER_CURRENCY = 1;
34.1376 + private static final int MODIFIER_PERCENT = 2;
34.1377 + private static final int MODIFIER_INTEGER = 3;
34.1378 +
34.1379 + private static final String[] NUMBER_MODIFIER_KEYWORDS = {
34.1380 + "",
34.1381 + "currency",
34.1382 + "percent",
34.1383 + "integer"
34.1384 + };
34.1385 +
34.1386 + // Indices for date-time modifiers
34.1387 + private static final int MODIFIER_SHORT = 1;
34.1388 + private static final int MODIFIER_MEDIUM = 2;
34.1389 + private static final int MODIFIER_LONG = 3;
34.1390 + private static final int MODIFIER_FULL = 4;
34.1391 +
34.1392 + private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
34.1393 + "",
34.1394 + "short",
34.1395 + "medium",
34.1396 + "long",
34.1397 + "full"
34.1398 + };
34.1399 +
34.1400 + // Date-time style values corresponding to the date-time modifiers.
34.1401 + private static final int[] DATE_TIME_MODIFIERS = {
34.1402 + DateFormat.DEFAULT,
34.1403 + DateFormat.SHORT,
34.1404 + DateFormat.MEDIUM,
34.1405 + DateFormat.LONG,
34.1406 + DateFormat.FULL,
34.1407 + };
34.1408 +
34.1409 + private void makeFormat(int position, int offsetNumber,
34.1410 + StringBuilder[] textSegments)
34.1411 + {
34.1412 + String[] segments = new String[textSegments.length];
34.1413 + for (int i = 0; i < textSegments.length; i++) {
34.1414 + StringBuilder oneseg = textSegments[i];
34.1415 + segments[i] = (oneseg != null) ? oneseg.toString() : "";
34.1416 + }
34.1417 +
34.1418 + // get the argument number
34.1419 + int argumentNumber;
34.1420 + try {
34.1421 + argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
34.1422 + } catch (NumberFormatException e) {
34.1423 + throw new IllegalArgumentException("can't parse argument number: "
34.1424 + + segments[SEG_INDEX], e);
34.1425 + }
34.1426 + if (argumentNumber < 0) {
34.1427 + throw new IllegalArgumentException("negative argument number: "
34.1428 + + argumentNumber);
34.1429 + }
34.1430 +
34.1431 + // resize format information arrays if necessary
34.1432 + if (offsetNumber >= formats.length) {
34.1433 + int newLength = formats.length * 2;
34.1434 + Format[] newFormats = new Format[newLength];
34.1435 + int[] newOffsets = new int[newLength];
34.1436 + int[] newArgumentNumbers = new int[newLength];
34.1437 + System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1);
34.1438 + System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1);
34.1439 + System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1);
34.1440 + formats = newFormats;
34.1441 + offsets = newOffsets;
34.1442 + argumentNumbers = newArgumentNumbers;
34.1443 + }
34.1444 + int oldMaxOffset = maxOffset;
34.1445 + maxOffset = offsetNumber;
34.1446 + offsets[offsetNumber] = segments[SEG_RAW].length();
34.1447 + argumentNumbers[offsetNumber] = argumentNumber;
34.1448 +
34.1449 + // now get the format
34.1450 + Format newFormat = null;
34.1451 + if (segments[SEG_TYPE].length() != 0) {
34.1452 + int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
34.1453 + switch (type) {
34.1454 + case TYPE_NULL:
34.1455 + // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
34.1456 + // are treated as "{0}".
34.1457 + break;
34.1458 +
34.1459 + case TYPE_NUMBER:
34.1460 + switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
34.1461 + case MODIFIER_DEFAULT:
34.1462 + newFormat = NumberFormat.getInstance(locale);
34.1463 + break;
34.1464 + case MODIFIER_CURRENCY:
34.1465 + newFormat = NumberFormat.getCurrencyInstance(locale);
34.1466 + break;
34.1467 + case MODIFIER_PERCENT:
34.1468 + newFormat = NumberFormat.getPercentInstance(locale);
34.1469 + break;
34.1470 + case MODIFIER_INTEGER:
34.1471 + newFormat = NumberFormat.getIntegerInstance(locale);
34.1472 + break;
34.1473 + default: // DecimalFormat pattern
34.1474 + try {
34.1475 + newFormat = new DecimalFormat(segments[SEG_MODIFIER],
34.1476 + DecimalFormatSymbols.getInstance(locale));
34.1477 + } catch (IllegalArgumentException e) {
34.1478 + maxOffset = oldMaxOffset;
34.1479 + throw e;
34.1480 + }
34.1481 + break;
34.1482 + }
34.1483 + break;
34.1484 +
34.1485 + case TYPE_DATE:
34.1486 + case TYPE_TIME:
34.1487 + int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
34.1488 + if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
34.1489 + if (type == TYPE_DATE) {
34.1490 + newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
34.1491 + locale);
34.1492 + } else {
34.1493 + newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
34.1494 + locale);
34.1495 + }
34.1496 + } else {
34.1497 + // SimpleDateFormat pattern
34.1498 + try {
34.1499 + newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
34.1500 + } catch (IllegalArgumentException e) {
34.1501 + maxOffset = oldMaxOffset;
34.1502 + throw e;
34.1503 + }
34.1504 + }
34.1505 + break;
34.1506 +
34.1507 + case TYPE_CHOICE:
34.1508 + try {
34.1509 + // ChoiceFormat pattern
34.1510 + newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
34.1511 + } catch (Exception e) {
34.1512 + maxOffset = oldMaxOffset;
34.1513 + throw new IllegalArgumentException("Choice Pattern incorrect: "
34.1514 + + segments[SEG_MODIFIER], e);
34.1515 + }
34.1516 + break;
34.1517 +
34.1518 + default:
34.1519 + maxOffset = oldMaxOffset;
34.1520 + throw new IllegalArgumentException("unknown format type: " +
34.1521 + segments[SEG_TYPE]);
34.1522 + }
34.1523 + }
34.1524 + formats[offsetNumber] = newFormat;
34.1525 + }
34.1526 +
34.1527 + private static final int findKeyword(String s, String[] list) {
34.1528 + for (int i = 0; i < list.length; ++i) {
34.1529 + if (s.equals(list[i]))
34.1530 + return i;
34.1531 + }
34.1532 +
34.1533 + // Try trimmed lowercase.
34.1534 + String ls = s.trim().toLowerCase(Locale.ROOT);
34.1535 + if (ls != s) {
34.1536 + for (int i = 0; i < list.length; ++i) {
34.1537 + if (ls.equals(list[i]))
34.1538 + return i;
34.1539 + }
34.1540 + }
34.1541 + return -1;
34.1542 + }
34.1543 +
34.1544 + private static final void copyAndFixQuotes(String source, int start, int end,
34.1545 + StringBuilder target) {
34.1546 + boolean quoted = false;
34.1547 +
34.1548 + for (int i = start; i < end; ++i) {
34.1549 + char ch = source.charAt(i);
34.1550 + if (ch == '{') {
34.1551 + if (!quoted) {
34.1552 + target.append('\'');
34.1553 + quoted = true;
34.1554 + }
34.1555 + target.append(ch);
34.1556 + } else if (ch == '\'') {
34.1557 + target.append("''");
34.1558 + } else {
34.1559 + if (quoted) {
34.1560 + target.append('\'');
34.1561 + quoted = false;
34.1562 + }
34.1563 + target.append(ch);
34.1564 + }
34.1565 + }
34.1566 + if (quoted) {
34.1567 + target.append('\'');
34.1568 + }
34.1569 + }
34.1570 +
34.1571 + /**
34.1572 + * After reading an object from the input stream, do a simple verification
34.1573 + * to maintain class invariants.
34.1574 + * @throws InvalidObjectException if the objects read from the stream is invalid.
34.1575 + */
34.1576 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
34.1577 + in.defaultReadObject();
34.1578 + boolean isValid = maxOffset >= -1
34.1579 + && formats.length > maxOffset
34.1580 + && offsets.length > maxOffset
34.1581 + && argumentNumbers.length > maxOffset;
34.1582 + if (isValid) {
34.1583 + int lastOffset = pattern.length() + 1;
34.1584 + for (int i = maxOffset; i >= 0; --i) {
34.1585 + if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
34.1586 + isValid = false;
34.1587 + break;
34.1588 + } else {
34.1589 + lastOffset = offsets[i];
34.1590 + }
34.1591 + }
34.1592 + }
34.1593 + if (!isValid) {
34.1594 + throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
34.1595 + }
34.1596 + }
34.1597 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/rt/emul/compact/src/main/java/java/text/NumberFormat.java Thu Oct 03 15:40:35 2013 +0200
35.3 @@ -0,0 +1,1162 @@
35.4 +/*
35.5 + * Copyright (c) 1996, 2010, 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.InvalidObjectException;
35.45 +import java.io.IOException;
35.46 +import java.io.ObjectInputStream;
35.47 +import java.io.ObjectOutputStream;
35.48 +import java.math.BigInteger;
35.49 +import java.math.RoundingMode;
35.50 +import java.text.spi.NumberFormatProvider;
35.51 +import java.util.Currency;
35.52 +import java.util.HashMap;
35.53 +import java.util.Hashtable;
35.54 +import java.util.Locale;
35.55 +import java.util.Map;
35.56 +import java.util.ResourceBundle;
35.57 +import java.util.concurrent.atomic.AtomicInteger;
35.58 +import java.util.concurrent.atomic.AtomicLong;
35.59 +import java.util.spi.LocaleServiceProvider;
35.60 +import sun.util.LocaleServiceProviderPool;
35.61 +import sun.util.resources.LocaleData;
35.62 +
35.63 +/**
35.64 + * <code>NumberFormat</code> is the abstract base class for all number
35.65 + * formats. This class provides the interface for formatting and parsing
35.66 + * numbers. <code>NumberFormat</code> also provides methods for determining
35.67 + * which locales have number formats, and what their names are.
35.68 + *
35.69 + * <p>
35.70 + * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
35.71 + * Your code can be completely independent of the locale conventions for
35.72 + * decimal points, thousands-separators, or even the particular decimal
35.73 + * digits used, or whether the number format is even decimal.
35.74 + *
35.75 + * <p>
35.76 + * To format a number for the current Locale, use one of the factory
35.77 + * class methods:
35.78 + * <blockquote>
35.79 + * <pre>
35.80 + * myString = NumberFormat.getInstance().format(myNumber);
35.81 + * </pre>
35.82 + * </blockquote>
35.83 + * If you are formatting multiple numbers, it is
35.84 + * more efficient to get the format and use it multiple times so that
35.85 + * the system doesn't have to fetch the information about the local
35.86 + * language and country conventions multiple times.
35.87 + * <blockquote>
35.88 + * <pre>
35.89 + * NumberFormat nf = NumberFormat.getInstance();
35.90 + * for (int i = 0; i < myNumber.length; ++i) {
35.91 + * output.println(nf.format(myNumber[i]) + "; ");
35.92 + * }
35.93 + * </pre>
35.94 + * </blockquote>
35.95 + * To format a number for a different Locale, specify it in the
35.96 + * call to <code>getInstance</code>.
35.97 + * <blockquote>
35.98 + * <pre>
35.99 + * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
35.100 + * </pre>
35.101 + * </blockquote>
35.102 + * You can also use a <code>NumberFormat</code> to parse numbers:
35.103 + * <blockquote>
35.104 + * <pre>
35.105 + * myNumber = nf.parse(myString);
35.106 + * </pre>
35.107 + * </blockquote>
35.108 + * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
35.109 + * normal number format. Use <code>getIntegerInstance</code> to get an
35.110 + * integer number format. Use <code>getCurrencyInstance</code> to get the
35.111 + * currency number format. And use <code>getPercentInstance</code> to get a
35.112 + * format for displaying percentages. With this format, a fraction like
35.113 + * 0.53 is displayed as 53%.
35.114 + *
35.115 + * <p>
35.116 + * You can also control the display of numbers with such methods as
35.117 + * <code>setMinimumFractionDigits</code>.
35.118 + * If you want even more control over the format or parsing,
35.119 + * or want to give your users more control,
35.120 + * you can try casting the <code>NumberFormat</code> you get from the factory methods
35.121 + * to a <code>DecimalFormat</code>. This will work for the vast majority
35.122 + * of locales; just remember to put it in a <code>try</code> block in case you
35.123 + * encounter an unusual one.
35.124 + *
35.125 + * <p>
35.126 + * NumberFormat and DecimalFormat are designed such that some controls
35.127 + * work for formatting and others work for parsing. The following is
35.128 + * the detailed description for each these control methods,
35.129 + * <p>
35.130 + * setParseIntegerOnly : only affects parsing, e.g.
35.131 + * if true, "3456.78" -> 3456 (and leaves the parse position just after index 6)
35.132 + * if false, "3456.78" -> 3456.78 (and leaves the parse position just after index 8)
35.133 + * This is independent of formatting. If you want to not show a decimal point
35.134 + * where there might be no digits after the decimal point, use
35.135 + * setDecimalSeparatorAlwaysShown.
35.136 + * <p>
35.137 + * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
35.138 + * there might be no digits after the decimal point, such as with a pattern
35.139 + * like "#,##0.##", e.g.,
35.140 + * if true, 3456.00 -> "3,456."
35.141 + * if false, 3456.00 -> "3456"
35.142 + * This is independent of parsing. If you want parsing to stop at the decimal
35.143 + * point, use setParseIntegerOnly.
35.144 + *
35.145 + * <p>
35.146 + * You can also use forms of the <code>parse</code> and <code>format</code>
35.147 + * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
35.148 + * allow you to:
35.149 + * <ul>
35.150 + * <li> progressively parse through pieces of a string
35.151 + * <li> align the decimal point and other areas
35.152 + * </ul>
35.153 + * For example, you can align numbers in two ways:
35.154 + * <ol>
35.155 + * <li> If you are using a monospaced font with spacing for alignment,
35.156 + * you can pass the <code>FieldPosition</code> in your format call, with
35.157 + * <code>field</code> = <code>INTEGER_FIELD</code>. On output,
35.158 + * <code>getEndIndex</code> will be set to the offset between the
35.159 + * last character of the integer and the decimal. Add
35.160 + * (desiredSpaceCount - getEndIndex) spaces at the front of the string.
35.161 + *
35.162 + * <li> If you are using proportional fonts,
35.163 + * instead of padding with spaces, measure the width
35.164 + * of the string in pixels from the start to <code>getEndIndex</code>.
35.165 + * Then move the pen by
35.166 + * (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
35.167 + * It also works where there is no decimal, but possibly additional
35.168 + * characters at the end, e.g., with parentheses in negative
35.169 + * numbers: "(12)" for -12.
35.170 + * </ol>
35.171 + *
35.172 + * <h4><a name="synchronization">Synchronization</a></h4>
35.173 + *
35.174 + * <p>
35.175 + * Number formats are generally not synchronized.
35.176 + * It is recommended to create separate format instances for each thread.
35.177 + * If multiple threads access a format concurrently, it must be synchronized
35.178 + * externally.
35.179 + *
35.180 + * @see DecimalFormat
35.181 + * @see ChoiceFormat
35.182 + * @author Mark Davis
35.183 + * @author Helena Shih
35.184 + */
35.185 +public abstract class NumberFormat extends Format {
35.186 +
35.187 + /**
35.188 + * Field constant used to construct a FieldPosition object. Signifies that
35.189 + * the position of the integer part of a formatted number should be returned.
35.190 + * @see java.text.FieldPosition
35.191 + */
35.192 + public static final int INTEGER_FIELD = 0;
35.193 +
35.194 + /**
35.195 + * Field constant used to construct a FieldPosition object. Signifies that
35.196 + * the position of the fraction part of a formatted number should be returned.
35.197 + * @see java.text.FieldPosition
35.198 + */
35.199 + public static final int FRACTION_FIELD = 1;
35.200 +
35.201 + /**
35.202 + * Sole constructor. (For invocation by subclass constructors, typically
35.203 + * implicit.)
35.204 + */
35.205 + protected NumberFormat() {
35.206 + }
35.207 +
35.208 + /**
35.209 + * Formats a number and appends the resulting text to the given string
35.210 + * buffer.
35.211 + * The number can be of any subclass of {@link java.lang.Number}.
35.212 + * <p>
35.213 + * This implementation extracts the number's value using
35.214 + * {@link java.lang.Number#longValue()} for all integral type values that
35.215 + * can be converted to <code>long</code> without loss of information,
35.216 + * including <code>BigInteger</code> values with a
35.217 + * {@link java.math.BigInteger#bitLength() bit length} of less than 64,
35.218 + * and {@link java.lang.Number#doubleValue()} for all other types. It
35.219 + * then calls
35.220 + * {@link #format(long,java.lang.StringBuffer,java.text.FieldPosition)}
35.221 + * or {@link #format(double,java.lang.StringBuffer,java.text.FieldPosition)}.
35.222 + * This may result in loss of magnitude information and precision for
35.223 + * <code>BigInteger</code> and <code>BigDecimal</code> values.
35.224 + * @param number the number to format
35.225 + * @param toAppendTo the <code>StringBuffer</code> to which the formatted
35.226 + * text is to be appended
35.227 + * @param pos On input: an alignment field, if desired.
35.228 + * On output: the offsets of the alignment field.
35.229 + * @return the value passed in as <code>toAppendTo</code>
35.230 + * @exception IllegalArgumentException if <code>number</code> is
35.231 + * null or not an instance of <code>Number</code>.
35.232 + * @exception NullPointerException if <code>toAppendTo</code> or
35.233 + * <code>pos</code> is null
35.234 + * @exception ArithmeticException if rounding is needed with rounding
35.235 + * mode being set to RoundingMode.UNNECESSARY
35.236 + * @see java.text.FieldPosition
35.237 + */
35.238 + public StringBuffer format(Object number,
35.239 + StringBuffer toAppendTo,
35.240 + FieldPosition pos) {
35.241 + if (number instanceof Long || number instanceof Integer ||
35.242 + number instanceof Short || number instanceof Byte ||
35.243 + number instanceof AtomicInteger || number instanceof AtomicLong ||
35.244 + (number instanceof BigInteger &&
35.245 + ((BigInteger)number).bitLength() < 64)) {
35.246 + return format(((Number)number).longValue(), toAppendTo, pos);
35.247 + } else if (number instanceof Number) {
35.248 + return format(((Number)number).doubleValue(), toAppendTo, pos);
35.249 + } else {
35.250 + throw new IllegalArgumentException("Cannot format given Object as a Number");
35.251 + }
35.252 + }
35.253 +
35.254 + /**
35.255 + * Parses text from a string to produce a <code>Number</code>.
35.256 + * <p>
35.257 + * The method attempts to parse text starting at the index given by
35.258 + * <code>pos</code>.
35.259 + * If parsing succeeds, then the index of <code>pos</code> is updated
35.260 + * to the index after the last character used (parsing does not necessarily
35.261 + * use all characters up to the end of the string), and the parsed
35.262 + * number is returned. The updated <code>pos</code> can be used to
35.263 + * indicate the starting point for the next call to this method.
35.264 + * If an error occurs, then the index of <code>pos</code> is not
35.265 + * changed, the error index of <code>pos</code> is set to the index of
35.266 + * the character where the error occurred, and null is returned.
35.267 + * <p>
35.268 + * See the {@link #parse(String, ParsePosition)} method for more information
35.269 + * on number parsing.
35.270 + *
35.271 + * @param source A <code>String</code>, part of which should be parsed.
35.272 + * @param pos A <code>ParsePosition</code> object with index and error
35.273 + * index information as described above.
35.274 + * @return A <code>Number</code> parsed from the string. In case of
35.275 + * error, returns null.
35.276 + * @exception NullPointerException if <code>pos</code> is null.
35.277 + */
35.278 + public final Object parseObject(String source, ParsePosition pos) {
35.279 + return parse(source, pos);
35.280 + }
35.281 +
35.282 + /**
35.283 + * Specialization of format.
35.284 + * @exception ArithmeticException if rounding is needed with rounding
35.285 + * mode being set to RoundingMode.UNNECESSARY
35.286 + * @see java.text.Format#format
35.287 + */
35.288 + public final String format(double number) {
35.289 + return format(number, new StringBuffer(),
35.290 + DontCareFieldPosition.INSTANCE).toString();
35.291 + }
35.292 +
35.293 + /**
35.294 + * Specialization of format.
35.295 + * @exception ArithmeticException if rounding is needed with rounding
35.296 + * mode being set to RoundingMode.UNNECESSARY
35.297 + * @see java.text.Format#format
35.298 + */
35.299 + public final String format(long number) {
35.300 + return format(number, new StringBuffer(),
35.301 + DontCareFieldPosition.INSTANCE).toString();
35.302 + }
35.303 +
35.304 + /**
35.305 + * Specialization of format.
35.306 + * @exception ArithmeticException if rounding is needed with rounding
35.307 + * mode being set to RoundingMode.UNNECESSARY
35.308 + * @see java.text.Format#format
35.309 + */
35.310 + public abstract StringBuffer format(double number,
35.311 + StringBuffer toAppendTo,
35.312 + FieldPosition pos);
35.313 +
35.314 + /**
35.315 + * Specialization of format.
35.316 + * @exception ArithmeticException if rounding is needed with rounding
35.317 + * mode being set to RoundingMode.UNNECESSARY
35.318 + * @see java.text.Format#format
35.319 + */
35.320 + public abstract StringBuffer format(long number,
35.321 + StringBuffer toAppendTo,
35.322 + FieldPosition pos);
35.323 +
35.324 + /**
35.325 + * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
35.326 + * Long.MAX_VALUE] and with no decimals), otherwise a Double.
35.327 + * If IntegerOnly is set, will stop at a decimal
35.328 + * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
35.329 + * after the 1).
35.330 + * Does not throw an exception; if no object can be parsed, index is
35.331 + * unchanged!
35.332 + * @see java.text.NumberFormat#isParseIntegerOnly
35.333 + * @see java.text.Format#parseObject
35.334 + */
35.335 + public abstract Number parse(String source, ParsePosition parsePosition);
35.336 +
35.337 + /**
35.338 + * Parses text from the beginning of the given string to produce a number.
35.339 + * The method may not use the entire text of the given string.
35.340 + * <p>
35.341 + * See the {@link #parse(String, ParsePosition)} method for more information
35.342 + * on number parsing.
35.343 + *
35.344 + * @param source A <code>String</code> whose beginning should be parsed.
35.345 + * @return A <code>Number</code> parsed from the string.
35.346 + * @exception ParseException if the beginning of the specified string
35.347 + * cannot be parsed.
35.348 + */
35.349 + public Number parse(String source) throws ParseException {
35.350 + ParsePosition parsePosition = new ParsePosition(0);
35.351 + Number result = parse(source, parsePosition);
35.352 + if (parsePosition.index == 0) {
35.353 + throw new ParseException("Unparseable number: \"" + source + "\"",
35.354 + parsePosition.errorIndex);
35.355 + }
35.356 + return result;
35.357 + }
35.358 +
35.359 + /**
35.360 + * Returns true if this format will parse numbers as integers only.
35.361 + * For example in the English locale, with ParseIntegerOnly true, the
35.362 + * string "1234." would be parsed as the integer value 1234 and parsing
35.363 + * would stop at the "." character. Of course, the exact format accepted
35.364 + * by the parse operation is locale dependant and determined by sub-classes
35.365 + * of NumberFormat.
35.366 + */
35.367 + public boolean isParseIntegerOnly() {
35.368 + return parseIntegerOnly;
35.369 + }
35.370 +
35.371 + /**
35.372 + * Sets whether or not numbers should be parsed as integers only.
35.373 + * @see #isParseIntegerOnly
35.374 + */
35.375 + public void setParseIntegerOnly(boolean value) {
35.376 + parseIntegerOnly = value;
35.377 + }
35.378 +
35.379 + //============== Locale Stuff =====================
35.380 +
35.381 + /**
35.382 + * Returns a general-purpose number format for the current default locale.
35.383 + * This is the same as calling
35.384 + * {@link #getNumberInstance() getNumberInstance()}.
35.385 + */
35.386 + public final static NumberFormat getInstance() {
35.387 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
35.388 + }
35.389 +
35.390 + /**
35.391 + * Returns a general-purpose number format for the specified locale.
35.392 + * This is the same as calling
35.393 + * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}.
35.394 + */
35.395 + public static NumberFormat getInstance(Locale inLocale) {
35.396 + return getInstance(inLocale, NUMBERSTYLE);
35.397 + }
35.398 +
35.399 + /**
35.400 + * Returns a general-purpose number format for the current default locale.
35.401 + */
35.402 + public final static NumberFormat getNumberInstance() {
35.403 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
35.404 + }
35.405 +
35.406 + /**
35.407 + * Returns a general-purpose number format for the specified locale.
35.408 + */
35.409 + public static NumberFormat getNumberInstance(Locale inLocale) {
35.410 + return getInstance(inLocale, NUMBERSTYLE);
35.411 + }
35.412 +
35.413 + /**
35.414 + * Returns an integer number format for the current default locale. The
35.415 + * returned number format is configured to round floating point numbers
35.416 + * to the nearest integer using half-even rounding (see {@link
35.417 + * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
35.418 + * and to parse only the integer part of an input string (see {@link
35.419 + * #isParseIntegerOnly isParseIntegerOnly}).
35.420 + *
35.421 + * @see #getRoundingMode()
35.422 + * @return a number format for integer values
35.423 + * @since 1.4
35.424 + */
35.425 + public final static NumberFormat getIntegerInstance() {
35.426 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
35.427 + }
35.428 +
35.429 + /**
35.430 + * Returns an integer number format for the specified locale. The
35.431 + * returned number format is configured to round floating point numbers
35.432 + * to the nearest integer using half-even rounding (see {@link
35.433 + * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
35.434 + * and to parse only the integer part of an input string (see {@link
35.435 + * #isParseIntegerOnly isParseIntegerOnly}).
35.436 + *
35.437 + * @see #getRoundingMode()
35.438 + * @return a number format for integer values
35.439 + * @since 1.4
35.440 + */
35.441 + public static NumberFormat getIntegerInstance(Locale inLocale) {
35.442 + return getInstance(inLocale, INTEGERSTYLE);
35.443 + }
35.444 +
35.445 + /**
35.446 + * Returns a currency format for the current default locale.
35.447 + */
35.448 + public final static NumberFormat getCurrencyInstance() {
35.449 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
35.450 + }
35.451 +
35.452 + /**
35.453 + * Returns a currency format for the specified locale.
35.454 + */
35.455 + public static NumberFormat getCurrencyInstance(Locale inLocale) {
35.456 + return getInstance(inLocale, CURRENCYSTYLE);
35.457 + }
35.458 +
35.459 + /**
35.460 + * Returns a percentage format for the current default locale.
35.461 + */
35.462 + public final static NumberFormat getPercentInstance() {
35.463 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
35.464 + }
35.465 +
35.466 + /**
35.467 + * Returns a percentage format for the specified locale.
35.468 + */
35.469 + public static NumberFormat getPercentInstance(Locale inLocale) {
35.470 + return getInstance(inLocale, PERCENTSTYLE);
35.471 + }
35.472 +
35.473 + /**
35.474 + * Returns a scientific format for the current default locale.
35.475 + */
35.476 + /*public*/ final static NumberFormat getScientificInstance() {
35.477 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE);
35.478 + }
35.479 +
35.480 + /**
35.481 + * Returns a scientific format for the specified locale.
35.482 + */
35.483 + /*public*/ static NumberFormat getScientificInstance(Locale inLocale) {
35.484 + return getInstance(inLocale, SCIENTIFICSTYLE);
35.485 + }
35.486 +
35.487 + /**
35.488 + * Returns an array of all locales for which the
35.489 + * <code>get*Instance</code> methods of this class can return
35.490 + * localized instances.
35.491 + * The returned array represents the union of locales supported by the Java
35.492 + * runtime and by installed
35.493 + * {@link java.text.spi.NumberFormatProvider NumberFormatProvider} implementations.
35.494 + * It must contain at least a <code>Locale</code> instance equal to
35.495 + * {@link java.util.Locale#US Locale.US}.
35.496 + *
35.497 + * @return An array of locales for which localized
35.498 + * <code>NumberFormat</code> instances are available.
35.499 + */
35.500 + public static Locale[] getAvailableLocales() {
35.501 + LocaleServiceProviderPool pool =
35.502 + LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
35.503 + return pool.getAvailableLocales();
35.504 + }
35.505 +
35.506 + /**
35.507 + * Overrides hashCode
35.508 + */
35.509 + public int hashCode() {
35.510 + return maximumIntegerDigits * 37 + maxFractionDigits;
35.511 + // just enough fields for a reasonable distribution
35.512 + }
35.513 +
35.514 + /**
35.515 + * Overrides equals
35.516 + */
35.517 + public boolean equals(Object obj) {
35.518 + if (obj == null) {
35.519 + return false;
35.520 + }
35.521 + if (this == obj) {
35.522 + return true;
35.523 + }
35.524 + if (getClass() != obj.getClass()) {
35.525 + return false;
35.526 + }
35.527 + NumberFormat other = (NumberFormat) obj;
35.528 + return (maximumIntegerDigits == other.maximumIntegerDigits
35.529 + && minimumIntegerDigits == other.minimumIntegerDigits
35.530 + && maximumFractionDigits == other.maximumFractionDigits
35.531 + && minimumFractionDigits == other.minimumFractionDigits
35.532 + && groupingUsed == other.groupingUsed
35.533 + && parseIntegerOnly == other.parseIntegerOnly);
35.534 + }
35.535 +
35.536 + /**
35.537 + * Overrides Cloneable
35.538 + */
35.539 + public Object clone() {
35.540 + NumberFormat other = (NumberFormat) super.clone();
35.541 + return other;
35.542 + }
35.543 +
35.544 + /**
35.545 + * Returns true if grouping is used in this format. For example, in the
35.546 + * English locale, with grouping on, the number 1234567 might be formatted
35.547 + * as "1,234,567". The grouping separator as well as the size of each group
35.548 + * is locale dependant and is determined by sub-classes of NumberFormat.
35.549 + * @see #setGroupingUsed
35.550 + */
35.551 + public boolean isGroupingUsed() {
35.552 + return groupingUsed;
35.553 + }
35.554 +
35.555 + /**
35.556 + * Set whether or not grouping will be used in this format.
35.557 + * @see #isGroupingUsed
35.558 + */
35.559 + public void setGroupingUsed(boolean newValue) {
35.560 + groupingUsed = newValue;
35.561 + }
35.562 +
35.563 + /**
35.564 + * Returns the maximum number of digits allowed in the integer portion of a
35.565 + * number.
35.566 + * @see #setMaximumIntegerDigits
35.567 + */
35.568 + public int getMaximumIntegerDigits() {
35.569 + return maximumIntegerDigits;
35.570 + }
35.571 +
35.572 + /**
35.573 + * Sets the maximum number of digits allowed in the integer portion of a
35.574 + * number. maximumIntegerDigits must be >= minimumIntegerDigits. If the
35.575 + * new value for maximumIntegerDigits is less than the current value
35.576 + * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
35.577 + * the new value.
35.578 + * @param newValue the maximum number of integer digits to be shown; if
35.579 + * less than zero, then zero is used. The concrete subclass may enforce an
35.580 + * upper limit to this value appropriate to the numeric type being formatted.
35.581 + * @see #getMaximumIntegerDigits
35.582 + */
35.583 + public void setMaximumIntegerDigits(int newValue) {
35.584 + maximumIntegerDigits = Math.max(0,newValue);
35.585 + if (minimumIntegerDigits > maximumIntegerDigits) {
35.586 + minimumIntegerDigits = maximumIntegerDigits;
35.587 + }
35.588 + }
35.589 +
35.590 + /**
35.591 + * Returns the minimum number of digits allowed in the integer portion of a
35.592 + * number.
35.593 + * @see #setMinimumIntegerDigits
35.594 + */
35.595 + public int getMinimumIntegerDigits() {
35.596 + return minimumIntegerDigits;
35.597 + }
35.598 +
35.599 + /**
35.600 + * Sets the minimum number of digits allowed in the integer portion of a
35.601 + * number. minimumIntegerDigits must be <= maximumIntegerDigits. If the
35.602 + * new value for minimumIntegerDigits exceeds the current value
35.603 + * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
35.604 + * the new value
35.605 + * @param newValue the minimum number of integer digits to be shown; if
35.606 + * less than zero, then zero is used. The concrete subclass may enforce an
35.607 + * upper limit to this value appropriate to the numeric type being formatted.
35.608 + * @see #getMinimumIntegerDigits
35.609 + */
35.610 + public void setMinimumIntegerDigits(int newValue) {
35.611 + minimumIntegerDigits = Math.max(0,newValue);
35.612 + if (minimumIntegerDigits > maximumIntegerDigits) {
35.613 + maximumIntegerDigits = minimumIntegerDigits;
35.614 + }
35.615 + }
35.616 +
35.617 + /**
35.618 + * Returns the maximum number of digits allowed in the fraction portion of a
35.619 + * number.
35.620 + * @see #setMaximumFractionDigits
35.621 + */
35.622 + public int getMaximumFractionDigits() {
35.623 + return maximumFractionDigits;
35.624 + }
35.625 +
35.626 + /**
35.627 + * Sets the maximum number of digits allowed in the fraction portion of a
35.628 + * number. maximumFractionDigits must be >= minimumFractionDigits. If the
35.629 + * new value for maximumFractionDigits is less than the current value
35.630 + * of minimumFractionDigits, then minimumFractionDigits will also be set to
35.631 + * the new value.
35.632 + * @param newValue the maximum number of fraction digits to be shown; if
35.633 + * less than zero, then zero is used. The concrete subclass may enforce an
35.634 + * upper limit to this value appropriate to the numeric type being formatted.
35.635 + * @see #getMaximumFractionDigits
35.636 + */
35.637 + public void setMaximumFractionDigits(int newValue) {
35.638 + maximumFractionDigits = Math.max(0,newValue);
35.639 + if (maximumFractionDigits < minimumFractionDigits) {
35.640 + minimumFractionDigits = maximumFractionDigits;
35.641 + }
35.642 + }
35.643 +
35.644 + /**
35.645 + * Returns the minimum number of digits allowed in the fraction portion of a
35.646 + * number.
35.647 + * @see #setMinimumFractionDigits
35.648 + */
35.649 + public int getMinimumFractionDigits() {
35.650 + return minimumFractionDigits;
35.651 + }
35.652 +
35.653 + /**
35.654 + * Sets the minimum number of digits allowed in the fraction portion of a
35.655 + * number. minimumFractionDigits must be <= maximumFractionDigits. If the
35.656 + * new value for minimumFractionDigits exceeds the current value
35.657 + * of maximumFractionDigits, then maximumIntegerDigits will also be set to
35.658 + * the new value
35.659 + * @param newValue the minimum number of fraction digits to be shown; if
35.660 + * less than zero, then zero is used. The concrete subclass may enforce an
35.661 + * upper limit to this value appropriate to the numeric type being formatted.
35.662 + * @see #getMinimumFractionDigits
35.663 + */
35.664 + public void setMinimumFractionDigits(int newValue) {
35.665 + minimumFractionDigits = Math.max(0,newValue);
35.666 + if (maximumFractionDigits < minimumFractionDigits) {
35.667 + maximumFractionDigits = minimumFractionDigits;
35.668 + }
35.669 + }
35.670 +
35.671 + /**
35.672 + * Gets the currency used by this number format when formatting
35.673 + * currency values. The initial value is derived in a locale dependent
35.674 + * way. The returned value may be null if no valid
35.675 + * currency could be determined and no currency has been set using
35.676 + * {@link #setCurrency(java.util.Currency) setCurrency}.
35.677 + * <p>
35.678 + * The default implementation throws
35.679 + * <code>UnsupportedOperationException</code>.
35.680 + *
35.681 + * @return the currency used by this number format, or <code>null</code>
35.682 + * @exception UnsupportedOperationException if the number format class
35.683 + * doesn't implement currency formatting
35.684 + * @since 1.4
35.685 + */
35.686 + public Currency getCurrency() {
35.687 + throw new UnsupportedOperationException();
35.688 + }
35.689 +
35.690 + /**
35.691 + * Sets the currency used by this number format when formatting
35.692 + * currency values. This does not update the minimum or maximum
35.693 + * number of fraction digits used by the number format.
35.694 + * <p>
35.695 + * The default implementation throws
35.696 + * <code>UnsupportedOperationException</code>.
35.697 + *
35.698 + * @param currency the new currency to be used by this number format
35.699 + * @exception UnsupportedOperationException if the number format class
35.700 + * doesn't implement currency formatting
35.701 + * @exception NullPointerException if <code>currency</code> is null
35.702 + * @since 1.4
35.703 + */
35.704 + public void setCurrency(Currency currency) {
35.705 + throw new UnsupportedOperationException();
35.706 + }
35.707 +
35.708 + /**
35.709 + * Gets the {@link java.math.RoundingMode} used in this NumberFormat.
35.710 + * The default implementation of this method in NumberFormat
35.711 + * always throws {@link java.lang.UnsupportedOperationException}.
35.712 + * Subclasses which handle different rounding modes should override
35.713 + * this method.
35.714 + *
35.715 + * @exception UnsupportedOperationException The default implementation
35.716 + * always throws this exception
35.717 + * @return The <code>RoundingMode</code> used for this NumberFormat.
35.718 + * @see #setRoundingMode(RoundingMode)
35.719 + * @since 1.6
35.720 + */
35.721 + public RoundingMode getRoundingMode() {
35.722 + throw new UnsupportedOperationException();
35.723 + }
35.724 +
35.725 + /**
35.726 + * Sets the {@link java.math.RoundingMode} used in this NumberFormat.
35.727 + * The default implementation of this method in NumberFormat always
35.728 + * throws {@link java.lang.UnsupportedOperationException}.
35.729 + * Subclasses which handle different rounding modes should override
35.730 + * this method.
35.731 + *
35.732 + * @exception UnsupportedOperationException The default implementation
35.733 + * always throws this exception
35.734 + * @exception NullPointerException if <code>roundingMode</code> is null
35.735 + * @param roundingMode The <code>RoundingMode</code> to be used
35.736 + * @see #getRoundingMode()
35.737 + * @since 1.6
35.738 + */
35.739 + public void setRoundingMode(RoundingMode roundingMode) {
35.740 + throw new UnsupportedOperationException();
35.741 + }
35.742 +
35.743 + // =======================privates===============================
35.744 +
35.745 + private static NumberFormat getInstance(Locale desiredLocale,
35.746 + int choice) {
35.747 + // Check whether a provider can provide an implementation that's closer
35.748 + // to the requested locale than what the Java runtime itself can provide.
35.749 + LocaleServiceProviderPool pool =
35.750 + LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
35.751 + if (pool.hasProviders()) {
35.752 + NumberFormat providersInstance = pool.getLocalizedObject(
35.753 + NumberFormatGetter.INSTANCE,
35.754 + desiredLocale,
35.755 + choice);
35.756 + if (providersInstance != null) {
35.757 + return providersInstance;
35.758 + }
35.759 + }
35.760 +
35.761 + /* try the cache first */
35.762 + String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale);
35.763 + if (numberPatterns == null) { /* cache miss */
35.764 + ResourceBundle resource = LocaleData.getNumberFormatData(desiredLocale);
35.765 + numberPatterns = resource.getStringArray("NumberPatterns");
35.766 + /* update cache */
35.767 + cachedLocaleData.put(desiredLocale, numberPatterns);
35.768 + }
35.769 +
35.770 + DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
35.771 + int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
35.772 + DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
35.773 +
35.774 + if (choice == INTEGERSTYLE) {
35.775 + format.setMaximumFractionDigits(0);
35.776 + format.setDecimalSeparatorAlwaysShown(false);
35.777 + format.setParseIntegerOnly(true);
35.778 + } else if (choice == CURRENCYSTYLE) {
35.779 + format.adjustForCurrencyDefaultFractionDigits();
35.780 + }
35.781 +
35.782 + return format;
35.783 + }
35.784 +
35.785 + /**
35.786 + * First, read in the default serializable data.
35.787 + *
35.788 + * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
35.789 + * the stream was written by JDK 1.1,
35.790 + * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
35.791 + * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
35.792 + * since the <code>int</code> fields were not present in JDK 1.1.
35.793 + * Finally, set serialVersionOnStream back to the maximum allowed value so that
35.794 + * default serialization will work properly if this object is streamed out again.
35.795 + *
35.796 + * <p>If <code>minimumIntegerDigits</code> is greater than
35.797 + * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
35.798 + * is greater than <code>maximumFractionDigits</code>, then the stream data
35.799 + * is invalid and this method throws an <code>InvalidObjectException</code>.
35.800 + * In addition, if any of these values is negative, then this method throws
35.801 + * an <code>InvalidObjectException</code>.
35.802 + *
35.803 + * @since 1.2
35.804 + */
35.805 + private void readObject(ObjectInputStream stream)
35.806 + throws IOException, ClassNotFoundException
35.807 + {
35.808 + stream.defaultReadObject();
35.809 + if (serialVersionOnStream < 1) {
35.810 + // Didn't have additional int fields, reassign to use them.
35.811 + maximumIntegerDigits = maxIntegerDigits;
35.812 + minimumIntegerDigits = minIntegerDigits;
35.813 + maximumFractionDigits = maxFractionDigits;
35.814 + minimumFractionDigits = minFractionDigits;
35.815 + }
35.816 + if (minimumIntegerDigits > maximumIntegerDigits ||
35.817 + minimumFractionDigits > maximumFractionDigits ||
35.818 + minimumIntegerDigits < 0 || minimumFractionDigits < 0) {
35.819 + throw new InvalidObjectException("Digit count range invalid");
35.820 + }
35.821 + serialVersionOnStream = currentSerialVersion;
35.822 + }
35.823 +
35.824 + /**
35.825 + * Write out the default serializable data, after first setting
35.826 + * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
35.827 + * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
35.828 + * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
35.829 + * with the JDK 1.1 version of the stream format.
35.830 + *
35.831 + * @since 1.2
35.832 + */
35.833 + private void writeObject(ObjectOutputStream stream)
35.834 + throws IOException
35.835 + {
35.836 + maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ?
35.837 + Byte.MAX_VALUE : (byte)maximumIntegerDigits;
35.838 + minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ?
35.839 + Byte.MAX_VALUE : (byte)minimumIntegerDigits;
35.840 + maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ?
35.841 + Byte.MAX_VALUE : (byte)maximumFractionDigits;
35.842 + minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ?
35.843 + Byte.MAX_VALUE : (byte)minimumFractionDigits;
35.844 + stream.defaultWriteObject();
35.845 + }
35.846 +
35.847 + /**
35.848 + * Cache to hold the NumberPatterns of a Locale.
35.849 + */
35.850 + private static final Hashtable cachedLocaleData = new Hashtable(3);
35.851 +
35.852 + // Constants used by factory methods to specify a style of format.
35.853 + private static final int NUMBERSTYLE = 0;
35.854 + private static final int CURRENCYSTYLE = 1;
35.855 + private static final int PERCENTSTYLE = 2;
35.856 + private static final int SCIENTIFICSTYLE = 3;
35.857 + private static final int INTEGERSTYLE = 4;
35.858 +
35.859 + /**
35.860 + * True if the grouping (i.e. thousands) separator is used when
35.861 + * formatting and parsing numbers.
35.862 + *
35.863 + * @serial
35.864 + * @see #isGroupingUsed
35.865 + */
35.866 + private boolean groupingUsed = true;
35.867 +
35.868 + /**
35.869 + * The maximum number of digits allowed in the integer portion of a
35.870 + * number. <code>maxIntegerDigits</code> must be greater than or equal to
35.871 + * <code>minIntegerDigits</code>.
35.872 + * <p>
35.873 + * <strong>Note:</strong> This field exists only for serialization
35.874 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
35.875 + * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
35.876 + * When writing to a stream, <code>maxIntegerDigits</code> is set to
35.877 + * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
35.878 + * whichever is smaller. When reading from a stream, this field is used
35.879 + * only if <code>serialVersionOnStream</code> is less than 1.
35.880 + *
35.881 + * @serial
35.882 + * @see #getMaximumIntegerDigits
35.883 + */
35.884 + private byte maxIntegerDigits = 40;
35.885 +
35.886 + /**
35.887 + * The minimum number of digits allowed in the integer portion of a
35.888 + * number. <code>minimumIntegerDigits</code> must be less than or equal to
35.889 + * <code>maximumIntegerDigits</code>.
35.890 + * <p>
35.891 + * <strong>Note:</strong> This field exists only for serialization
35.892 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
35.893 + * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
35.894 + * When writing to a stream, <code>minIntegerDigits</code> is set to
35.895 + * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
35.896 + * whichever is smaller. When reading from a stream, this field is used
35.897 + * only if <code>serialVersionOnStream</code> is less than 1.
35.898 + *
35.899 + * @serial
35.900 + * @see #getMinimumIntegerDigits
35.901 + */
35.902 + private byte minIntegerDigits = 1;
35.903 +
35.904 + /**
35.905 + * The maximum number of digits allowed in the fractional portion of a
35.906 + * number. <code>maximumFractionDigits</code> must be greater than or equal to
35.907 + * <code>minimumFractionDigits</code>.
35.908 + * <p>
35.909 + * <strong>Note:</strong> This field exists only for serialization
35.910 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
35.911 + * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
35.912 + * When writing to a stream, <code>maxFractionDigits</code> is set to
35.913 + * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
35.914 + * whichever is smaller. When reading from a stream, this field is used
35.915 + * only if <code>serialVersionOnStream</code> is less than 1.
35.916 + *
35.917 + * @serial
35.918 + * @see #getMaximumFractionDigits
35.919 + */
35.920 + private byte maxFractionDigits = 3; // invariant, >= minFractionDigits
35.921 +
35.922 + /**
35.923 + * The minimum number of digits allowed in the fractional portion of a
35.924 + * number. <code>minimumFractionDigits</code> must be less than or equal to
35.925 + * <code>maximumFractionDigits</code>.
35.926 + * <p>
35.927 + * <strong>Note:</strong> This field exists only for serialization
35.928 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
35.929 + * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
35.930 + * When writing to a stream, <code>minFractionDigits</code> is set to
35.931 + * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
35.932 + * whichever is smaller. When reading from a stream, this field is used
35.933 + * only if <code>serialVersionOnStream</code> is less than 1.
35.934 + *
35.935 + * @serial
35.936 + * @see #getMinimumFractionDigits
35.937 + */
35.938 + private byte minFractionDigits = 0;
35.939 +
35.940 + /**
35.941 + * True if this format will parse numbers as integers only.
35.942 + *
35.943 + * @serial
35.944 + * @see #isParseIntegerOnly
35.945 + */
35.946 + private boolean parseIntegerOnly = false;
35.947 +
35.948 + // new fields for 1.2. byte is too small for integer digits.
35.949 +
35.950 + /**
35.951 + * The maximum number of digits allowed in the integer portion of a
35.952 + * number. <code>maximumIntegerDigits</code> must be greater than or equal to
35.953 + * <code>minimumIntegerDigits</code>.
35.954 + *
35.955 + * @serial
35.956 + * @since 1.2
35.957 + * @see #getMaximumIntegerDigits
35.958 + */
35.959 + private int maximumIntegerDigits = 40;
35.960 +
35.961 + /**
35.962 + * The minimum number of digits allowed in the integer portion of a
35.963 + * number. <code>minimumIntegerDigits</code> must be less than or equal to
35.964 + * <code>maximumIntegerDigits</code>.
35.965 + *
35.966 + * @serial
35.967 + * @since 1.2
35.968 + * @see #getMinimumIntegerDigits
35.969 + */
35.970 + private int minimumIntegerDigits = 1;
35.971 +
35.972 + /**
35.973 + * The maximum number of digits allowed in the fractional portion of a
35.974 + * number. <code>maximumFractionDigits</code> must be greater than or equal to
35.975 + * <code>minimumFractionDigits</code>.
35.976 + *
35.977 + * @serial
35.978 + * @since 1.2
35.979 + * @see #getMaximumFractionDigits
35.980 + */
35.981 + private int maximumFractionDigits = 3; // invariant, >= minFractionDigits
35.982 +
35.983 + /**
35.984 + * The minimum number of digits allowed in the fractional portion of a
35.985 + * number. <code>minimumFractionDigits</code> must be less than or equal to
35.986 + * <code>maximumFractionDigits</code>.
35.987 + *
35.988 + * @serial
35.989 + * @since 1.2
35.990 + * @see #getMinimumFractionDigits
35.991 + */
35.992 + private int minimumFractionDigits = 0;
35.993 +
35.994 + static final int currentSerialVersion = 1;
35.995 +
35.996 + /**
35.997 + * Describes the version of <code>NumberFormat</code> present on the stream.
35.998 + * Possible values are:
35.999 + * <ul>
35.1000 + * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
35.1001 + * In this version, the <code>int</code> fields such as
35.1002 + * <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
35.1003 + * fields such as <code>maxIntegerDigits</code> are used instead.
35.1004 + *
35.1005 + * <li><b>1</b>: the 1.2 version of the stream format. The values of the
35.1006 + * <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
35.1007 + * and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
35.1008 + * are used instead.
35.1009 + * </ul>
35.1010 + * When streaming out a <code>NumberFormat</code>, the most recent format
35.1011 + * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
35.1012 + * is always written.
35.1013 + *
35.1014 + * @serial
35.1015 + * @since 1.2
35.1016 + */
35.1017 + private int serialVersionOnStream = currentSerialVersion;
35.1018 +
35.1019 + // Removed "implements Cloneable" clause. Needs to update serialization
35.1020 + // ID for backward compatibility.
35.1021 + static final long serialVersionUID = -2308460125733713944L;
35.1022 +
35.1023 +
35.1024 + //
35.1025 + // class for AttributedCharacterIterator attributes
35.1026 + //
35.1027 + /**
35.1028 + * Defines constants that are used as attribute keys in the
35.1029 + * <code>AttributedCharacterIterator</code> returned
35.1030 + * from <code>NumberFormat.formatToCharacterIterator</code> and as
35.1031 + * field identifiers in <code>FieldPosition</code>.
35.1032 + *
35.1033 + * @since 1.4
35.1034 + */
35.1035 + public static class Field extends Format.Field {
35.1036 +
35.1037 + // Proclaim serial compatibility with 1.4 FCS
35.1038 + private static final long serialVersionUID = 7494728892700160890L;
35.1039 +
35.1040 + // table of all instances in this class, used by readResolve
35.1041 + private static final Map instanceMap = new HashMap(11);
35.1042 +
35.1043 + /**
35.1044 + * Creates a Field instance with the specified
35.1045 + * name.
35.1046 + *
35.1047 + * @param name Name of the attribute
35.1048 + */
35.1049 + protected Field(String name) {
35.1050 + super(name);
35.1051 + if (this.getClass() == NumberFormat.Field.class) {
35.1052 + instanceMap.put(name, this);
35.1053 + }
35.1054 + }
35.1055 +
35.1056 + /**
35.1057 + * Resolves instances being deserialized to the predefined constants.
35.1058 + *
35.1059 + * @throws InvalidObjectException if the constant could not be resolved.
35.1060 + * @return resolved NumberFormat.Field constant
35.1061 + */
35.1062 + protected Object readResolve() throws InvalidObjectException {
35.1063 + if (this.getClass() != NumberFormat.Field.class) {
35.1064 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
35.1065 + }
35.1066 +
35.1067 + Object instance = instanceMap.get(getName());
35.1068 + if (instance != null) {
35.1069 + return instance;
35.1070 + } else {
35.1071 + throw new InvalidObjectException("unknown attribute name");
35.1072 + }
35.1073 + }
35.1074 +
35.1075 + /**
35.1076 + * Constant identifying the integer field.
35.1077 + */
35.1078 + public static final Field INTEGER = new Field("integer");
35.1079 +
35.1080 + /**
35.1081 + * Constant identifying the fraction field.
35.1082 + */
35.1083 + public static final Field FRACTION = new Field("fraction");
35.1084 +
35.1085 + /**
35.1086 + * Constant identifying the exponent field.
35.1087 + */
35.1088 + public static final Field EXPONENT = new Field("exponent");
35.1089 +
35.1090 + /**
35.1091 + * Constant identifying the decimal separator field.
35.1092 + */
35.1093 + public static final Field DECIMAL_SEPARATOR =
35.1094 + new Field("decimal separator");
35.1095 +
35.1096 + /**
35.1097 + * Constant identifying the sign field.
35.1098 + */
35.1099 + public static final Field SIGN = new Field("sign");
35.1100 +
35.1101 + /**
35.1102 + * Constant identifying the grouping separator field.
35.1103 + */
35.1104 + public static final Field GROUPING_SEPARATOR =
35.1105 + new Field("grouping separator");
35.1106 +
35.1107 + /**
35.1108 + * Constant identifying the exponent symbol field.
35.1109 + */
35.1110 + public static final Field EXPONENT_SYMBOL = new
35.1111 + Field("exponent symbol");
35.1112 +
35.1113 + /**
35.1114 + * Constant identifying the percent field.
35.1115 + */
35.1116 + public static final Field PERCENT = new Field("percent");
35.1117 +
35.1118 + /**
35.1119 + * Constant identifying the permille field.
35.1120 + */
35.1121 + public static final Field PERMILLE = new Field("per mille");
35.1122 +
35.1123 + /**
35.1124 + * Constant identifying the currency field.
35.1125 + */
35.1126 + public static final Field CURRENCY = new Field("currency");
35.1127 +
35.1128 + /**
35.1129 + * Constant identifying the exponent sign field.
35.1130 + */
35.1131 + public static final Field EXPONENT_SIGN = new Field("exponent sign");
35.1132 + }
35.1133 +
35.1134 + /**
35.1135 + * Obtains a NumberFormat instance from a NumberFormatProvider implementation.
35.1136 + */
35.1137 + private static class NumberFormatGetter
35.1138 + implements LocaleServiceProviderPool.LocalizedObjectGetter<NumberFormatProvider,
35.1139 + NumberFormat> {
35.1140 + private static final NumberFormatGetter INSTANCE = new NumberFormatGetter();
35.1141 +
35.1142 + public NumberFormat getObject(NumberFormatProvider numberFormatProvider,
35.1143 + Locale locale,
35.1144 + String key,
35.1145 + Object... params) {
35.1146 + assert params.length == 1;
35.1147 + int choice = (Integer)params[0];
35.1148 +
35.1149 + switch (choice) {
35.1150 + case NUMBERSTYLE:
35.1151 + return numberFormatProvider.getNumberInstance(locale);
35.1152 + case PERCENTSTYLE:
35.1153 + return numberFormatProvider.getPercentInstance(locale);
35.1154 + case CURRENCYSTYLE:
35.1155 + return numberFormatProvider.getCurrencyInstance(locale);
35.1156 + case INTEGERSTYLE:
35.1157 + return numberFormatProvider.getIntegerInstance(locale);
35.1158 + default:
35.1159 + assert false : choice;
35.1160 + }
35.1161 +
35.1162 + return null;
35.1163 + }
35.1164 + }
35.1165 +}
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/rt/emul/compact/src/main/java/java/text/ParseException.java Thu Oct 03 15:40:35 2013 +0200
36.3 @@ -0,0 +1,78 @@
36.4 +/*
36.5 + * Copyright (c) 1996, 1998, 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 +/**
36.45 + * Signals that an error has been reached unexpectedly
36.46 + * while parsing.
36.47 + * @see java.lang.Exception
36.48 + * @see java.text.Format
36.49 + * @see java.text.FieldPosition
36.50 + * @author Mark Davis
36.51 + */
36.52 +public
36.53 +class ParseException extends Exception {
36.54 +
36.55 + /**
36.56 + * Constructs a ParseException with the specified detail message and
36.57 + * offset.
36.58 + * A detail message is a String that describes this particular exception.
36.59 + * @param s the detail message
36.60 + * @param errorOffset the position where the error is found while parsing.
36.61 + */
36.62 + public ParseException(String s, int errorOffset) {
36.63 + super(s);
36.64 + this.errorOffset = errorOffset;
36.65 + }
36.66 +
36.67 + /**
36.68 + * Returns the position where the error was found.
36.69 + */
36.70 + public int getErrorOffset () {
36.71 + return errorOffset;
36.72 + }
36.73 +
36.74 + //============ privates ============
36.75 + /**
36.76 + * The zero-based character offset into the string being parsed at which
36.77 + * the error was found during parsing.
36.78 + * @serial
36.79 + */
36.80 + private int errorOffset;
36.81 +}
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/rt/emul/compact/src/main/java/java/text/ParsePosition.java Thu Oct 03 15:40:35 2013 +0200
37.3 @@ -0,0 +1,139 @@
37.4 +/*
37.5 + * Copyright (c) 1996, 2002, 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 +
37.45 +/**
37.46 + * <code>ParsePosition</code> is a simple class used by <code>Format</code>
37.47 + * and its subclasses to keep track of the current position during parsing.
37.48 + * The <code>parseObject</code> method in the various <code>Format</code>
37.49 + * classes requires a <code>ParsePosition</code> object as an argument.
37.50 + *
37.51 + * <p>
37.52 + * By design, as you parse through a string with different formats,
37.53 + * you can use the same <code>ParsePosition</code>, since the index parameter
37.54 + * records the current position.
37.55 + *
37.56 + * @author Mark Davis
37.57 + * @see java.text.Format
37.58 + */
37.59 +
37.60 +public class ParsePosition {
37.61 +
37.62 + /**
37.63 + * Input: the place you start parsing.
37.64 + * <br>Output: position where the parse stopped.
37.65 + * This is designed to be used serially,
37.66 + * with each call setting index up for the next one.
37.67 + */
37.68 + int index = 0;
37.69 + int errorIndex = -1;
37.70 +
37.71 + /**
37.72 + * Retrieve the current parse position. On input to a parse method, this
37.73 + * is the index of the character at which parsing will begin; on output, it
37.74 + * is the index of the character following the last character parsed.
37.75 + */
37.76 + public int getIndex() {
37.77 + return index;
37.78 + }
37.79 +
37.80 + /**
37.81 + * Set the current parse position.
37.82 + */
37.83 + public void setIndex(int index) {
37.84 + this.index = index;
37.85 + }
37.86 +
37.87 + /**
37.88 + * Create a new ParsePosition with the given initial index.
37.89 + */
37.90 + public ParsePosition(int index) {
37.91 + this.index = index;
37.92 + }
37.93 + /**
37.94 + * Set the index at which a parse error occurred. Formatters
37.95 + * should set this before returning an error code from their
37.96 + * parseObject method. The default value is -1 if this is not set.
37.97 + * @since 1.2
37.98 + */
37.99 + public void setErrorIndex(int ei)
37.100 + {
37.101 + errorIndex = ei;
37.102 + }
37.103 +
37.104 + /**
37.105 + * Retrieve the index at which an error occurred, or -1 if the
37.106 + * error index has not been set.
37.107 + * @since 1.2
37.108 + */
37.109 + public int getErrorIndex()
37.110 + {
37.111 + return errorIndex;
37.112 + }
37.113 + /**
37.114 + * Overrides equals
37.115 + */
37.116 + public boolean equals(Object obj)
37.117 + {
37.118 + if (obj == null) return false;
37.119 + if (!(obj instanceof ParsePosition))
37.120 + return false;
37.121 + ParsePosition other = (ParsePosition) obj;
37.122 + return (index == other.index && errorIndex == other.errorIndex);
37.123 + }
37.124 +
37.125 + /**
37.126 + * Returns a hash code for this ParsePosition.
37.127 + * @return a hash code value for this object
37.128 + */
37.129 + public int hashCode() {
37.130 + return (errorIndex << 16) | index;
37.131 + }
37.132 +
37.133 + /**
37.134 + * Return a string representation of this ParsePosition.
37.135 + * @return a string representation of this object
37.136 + */
37.137 + public String toString() {
37.138 + return getClass().getName() +
37.139 + "[index=" + index +
37.140 + ",errorIndex=" + errorIndex + ']';
37.141 + }
37.142 +}
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/rt/emul/compact/src/main/java/java/text/SimpleDateFormat.java Thu Oct 03 15:40:35 2013 +0200
38.3 @@ -0,0 +1,2350 @@
38.4 +/*
38.5 + * Copyright (c) 1996, 2011, 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 - 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 +import java.io.IOException;
38.45 +import java.io.InvalidObjectException;
38.46 +import java.io.ObjectInputStream;
38.47 +import java.util.Calendar;
38.48 +import java.util.Date;
38.49 +import java.util.GregorianCalendar;
38.50 +import java.util.Locale;
38.51 +import java.util.Map;
38.52 +import java.util.MissingResourceException;
38.53 +import java.util.ResourceBundle;
38.54 +import java.util.SimpleTimeZone;
38.55 +import java.util.TimeZone;
38.56 +import java.util.concurrent.ConcurrentHashMap;
38.57 +import java.util.concurrent.ConcurrentMap;
38.58 +import sun.util.calendar.CalendarUtils;
38.59 +import sun.util.calendar.ZoneInfoFile;
38.60 +import sun.util.resources.LocaleData;
38.61 +
38.62 +import static java.text.DateFormatSymbols.*;
38.63 +
38.64 +/**
38.65 + * <code>SimpleDateFormat</code> is a concrete class for formatting and
38.66 + * parsing dates in a locale-sensitive manner. It allows for formatting
38.67 + * (date -> text), parsing (text -> date), and normalization.
38.68 + *
38.69 + * <p>
38.70 + * <code>SimpleDateFormat</code> allows you to start by choosing
38.71 + * any user-defined patterns for date-time formatting. However, you
38.72 + * are encouraged to create a date-time formatter with either
38.73 + * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
38.74 + * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
38.75 + * of these class methods can return a date/time formatter initialized
38.76 + * with a default format pattern. You may modify the format pattern
38.77 + * using the <code>applyPattern</code> methods as desired.
38.78 + * For more information on using these methods, see
38.79 + * {@link DateFormat}.
38.80 + *
38.81 + * <h4>Date and Time Patterns</h4>
38.82 + * <p>
38.83 + * Date and time formats are specified by <em>date and time pattern</em>
38.84 + * strings.
38.85 + * Within date and time pattern strings, unquoted letters from
38.86 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
38.87 + * <code>'z'</code> are interpreted as pattern letters representing the
38.88 + * components of a date or time string.
38.89 + * Text can be quoted using single quotes (<code>'</code>) to avoid
38.90 + * interpretation.
38.91 + * <code>"''"</code> represents a single quote.
38.92 + * All other characters are not interpreted; they're simply copied into the
38.93 + * output string during formatting or matched against the input string
38.94 + * during parsing.
38.95 + * <p>
38.96 + * The following pattern letters are defined (all other characters from
38.97 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
38.98 + * <code>'z'</code> are reserved):
38.99 + * <blockquote>
38.100 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart shows pattern letters, date/time component, presentation, and examples.">
38.101 + * <tr bgcolor="#ccccff">
38.102 + * <th align=left>Letter
38.103 + * <th align=left>Date or Time Component
38.104 + * <th align=left>Presentation
38.105 + * <th align=left>Examples
38.106 + * <tr>
38.107 + * <td><code>G</code>
38.108 + * <td>Era designator
38.109 + * <td><a href="#text">Text</a>
38.110 + * <td><code>AD</code>
38.111 + * <tr bgcolor="#eeeeff">
38.112 + * <td><code>y</code>
38.113 + * <td>Year
38.114 + * <td><a href="#year">Year</a>
38.115 + * <td><code>1996</code>; <code>96</code>
38.116 + * <tr>
38.117 + * <td><code>Y</code>
38.118 + * <td>Week year
38.119 + * <td><a href="#year">Year</a>
38.120 + * <td><code>2009</code>; <code>09</code>
38.121 + * <tr bgcolor="#eeeeff">
38.122 + * <td><code>M</code>
38.123 + * <td>Month in year
38.124 + * <td><a href="#month">Month</a>
38.125 + * <td><code>July</code>; <code>Jul</code>; <code>07</code>
38.126 + * <tr>
38.127 + * <td><code>w</code>
38.128 + * <td>Week in year
38.129 + * <td><a href="#number">Number</a>
38.130 + * <td><code>27</code>
38.131 + * <tr bgcolor="#eeeeff">
38.132 + * <td><code>W</code>
38.133 + * <td>Week in month
38.134 + * <td><a href="#number">Number</a>
38.135 + * <td><code>2</code>
38.136 + * <tr>
38.137 + * <td><code>D</code>
38.138 + * <td>Day in year
38.139 + * <td><a href="#number">Number</a>
38.140 + * <td><code>189</code>
38.141 + * <tr bgcolor="#eeeeff">
38.142 + * <td><code>d</code>
38.143 + * <td>Day in month
38.144 + * <td><a href="#number">Number</a>
38.145 + * <td><code>10</code>
38.146 + * <tr>
38.147 + * <td><code>F</code>
38.148 + * <td>Day of week in month
38.149 + * <td><a href="#number">Number</a>
38.150 + * <td><code>2</code>
38.151 + * <tr bgcolor="#eeeeff">
38.152 + * <td><code>E</code>
38.153 + * <td>Day name in week
38.154 + * <td><a href="#text">Text</a>
38.155 + * <td><code>Tuesday</code>; <code>Tue</code>
38.156 + * <tr>
38.157 + * <td><code>u</code>
38.158 + * <td>Day number of week (1 = Monday, ..., 7 = Sunday)
38.159 + * <td><a href="#number">Number</a>
38.160 + * <td><code>1</code>
38.161 + * <tr bgcolor="#eeeeff">
38.162 + * <td><code>a</code>
38.163 + * <td>Am/pm marker
38.164 + * <td><a href="#text">Text</a>
38.165 + * <td><code>PM</code>
38.166 + * <tr>
38.167 + * <td><code>H</code>
38.168 + * <td>Hour in day (0-23)
38.169 + * <td><a href="#number">Number</a>
38.170 + * <td><code>0</code>
38.171 + * <tr bgcolor="#eeeeff">
38.172 + * <td><code>k</code>
38.173 + * <td>Hour in day (1-24)
38.174 + * <td><a href="#number">Number</a>
38.175 + * <td><code>24</code>
38.176 + * <tr>
38.177 + * <td><code>K</code>
38.178 + * <td>Hour in am/pm (0-11)
38.179 + * <td><a href="#number">Number</a>
38.180 + * <td><code>0</code>
38.181 + * <tr bgcolor="#eeeeff">
38.182 + * <td><code>h</code>
38.183 + * <td>Hour in am/pm (1-12)
38.184 + * <td><a href="#number">Number</a>
38.185 + * <td><code>12</code>
38.186 + * <tr>
38.187 + * <td><code>m</code>
38.188 + * <td>Minute in hour
38.189 + * <td><a href="#number">Number</a>
38.190 + * <td><code>30</code>
38.191 + * <tr bgcolor="#eeeeff">
38.192 + * <td><code>s</code>
38.193 + * <td>Second in minute
38.194 + * <td><a href="#number">Number</a>
38.195 + * <td><code>55</code>
38.196 + * <tr>
38.197 + * <td><code>S</code>
38.198 + * <td>Millisecond
38.199 + * <td><a href="#number">Number</a>
38.200 + * <td><code>978</code>
38.201 + * <tr bgcolor="#eeeeff">
38.202 + * <td><code>z</code>
38.203 + * <td>Time zone
38.204 + * <td><a href="#timezone">General time zone</a>
38.205 + * <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
38.206 + * <tr>
38.207 + * <td><code>Z</code>
38.208 + * <td>Time zone
38.209 + * <td><a href="#rfc822timezone">RFC 822 time zone</a>
38.210 + * <td><code>-0800</code>
38.211 + * <tr bgcolor="#eeeeff">
38.212 + * <td><code>X</code>
38.213 + * <td>Time zone
38.214 + * <td><a href="#iso8601timezone">ISO 8601 time zone</a>
38.215 + * <td><code>-08</code>; <code>-0800</code>; <code>-08:00</code>
38.216 + * </table>
38.217 + * </blockquote>
38.218 + * Pattern letters are usually repeated, as their number determines the
38.219 + * exact presentation:
38.220 + * <ul>
38.221 + * <li><strong><a name="text">Text:</a></strong>
38.222 + * For formatting, if the number of pattern letters is 4 or more,
38.223 + * the full form is used; otherwise a short or abbreviated form
38.224 + * is used if available.
38.225 + * For parsing, both forms are accepted, independent of the number
38.226 + * of pattern letters.<br><br></li>
38.227 + * <li><strong><a name="number">Number:</a></strong>
38.228 + * For formatting, the number of pattern letters is the minimum
38.229 + * number of digits, and shorter numbers are zero-padded to this amount.
38.230 + * For parsing, the number of pattern letters is ignored unless
38.231 + * it's needed to separate two adjacent fields.<br><br></li>
38.232 + * <li><strong><a name="year">Year:</a></strong>
38.233 + * If the formatter's {@link #getCalendar() Calendar} is the Gregorian
38.234 + * calendar, the following rules are applied.<br>
38.235 + * <ul>
38.236 + * <li>For formatting, if the number of pattern letters is 2, the year
38.237 + * is truncated to 2 digits; otherwise it is interpreted as a
38.238 + * <a href="#number">number</a>.
38.239 + * <li>For parsing, if the number of pattern letters is more than 2,
38.240 + * the year is interpreted literally, regardless of the number of
38.241 + * digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to
38.242 + * Jan 11, 12 A.D.
38.243 + * <li>For parsing with the abbreviated year pattern ("y" or "yy"),
38.244 + * <code>SimpleDateFormat</code> must interpret the abbreviated year
38.245 + * relative to some century. It does this by adjusting dates to be
38.246 + * within 80 years before and 20 years after the time the <code>SimpleDateFormat</code>
38.247 + * instance is created. For example, using a pattern of "MM/dd/yy" and a
38.248 + * <code>SimpleDateFormat</code> instance created on Jan 1, 1997, the string
38.249 + * "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
38.250 + * would be interpreted as May 4, 1964.
38.251 + * During parsing, only strings consisting of exactly two digits, as defined by
38.252 + * {@link Character#isDigit(char)}, will be parsed into the default century.
38.253 + * Any other numeric string, such as a one digit string, a three or more digit
38.254 + * string, or a two digit string that isn't all digits (for example, "-1"), is
38.255 + * interpreted literally. So "01/02/3" or "01/02/003" are parsed, using the
38.256 + * same pattern, as Jan 2, 3 AD. Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
38.257 + * </ul>
38.258 + * Otherwise, calendar system specific forms are applied.
38.259 + * For both formatting and parsing, if the number of pattern
38.260 + * letters is 4 or more, a calendar specific {@linkplain
38.261 + * Calendar#LONG long form} is used. Otherwise, a calendar
38.262 + * specific {@linkplain Calendar#SHORT short or abbreviated form}
38.263 + * is used.<br>
38.264 + * <br>
38.265 + * If week year {@code 'Y'} is specified and the {@linkplain
38.266 + * #getCalendar() calendar} doesn't support any <a
38.267 + * href="../util/GregorianCalendar.html#week_year"> week
38.268 + * years</a>, the calendar year ({@code 'y'}) is used instead. The
38.269 + * support of week years can be tested with a call to {@link
38.270 + * DateFormat#getCalendar() getCalendar()}.{@link
38.271 + * java.util.Calendar#isWeekDateSupported()
38.272 + * isWeekDateSupported()}.<br><br></li>
38.273 + * <li><strong><a name="month">Month:</a></strong>
38.274 + * If the number of pattern letters is 3 or more, the month is
38.275 + * interpreted as <a href="#text">text</a>; otherwise,
38.276 + * it is interpreted as a <a href="#number">number</a>.<br><br></li>
38.277 + * <li><strong><a name="timezone">General time zone:</a></strong>
38.278 + * Time zones are interpreted as <a href="#text">text</a> if they have
38.279 + * names. For time zones representing a GMT offset value, the
38.280 + * following syntax is used:
38.281 + * <pre>
38.282 + * <a name="GMTOffsetTimeZone"><i>GMTOffsetTimeZone:</i></a>
38.283 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
38.284 + * <i>Sign:</i> one of
38.285 + * <code>+ -</code>
38.286 + * <i>Hours:</i>
38.287 + * <i>Digit</i>
38.288 + * <i>Digit</i> <i>Digit</i>
38.289 + * <i>Minutes:</i>
38.290 + * <i>Digit</i> <i>Digit</i>
38.291 + * <i>Digit:</i> one of
38.292 + * <code>0 1 2 3 4 5 6 7 8 9</code></pre>
38.293 + * <i>Hours</i> must be between 0 and 23, and <i>Minutes</i> must be between
38.294 + * 00 and 59. The format is locale independent and digits must be taken
38.295 + * from the Basic Latin block of the Unicode standard.
38.296 + * <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
38.297 + * accepted.<br><br></li>
38.298 + * <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
38.299 + * For formatting, the RFC 822 4-digit time zone format is used:
38.300 + *
38.301 + * <pre>
38.302 + * <i>RFC822TimeZone:</i>
38.303 + * <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
38.304 + * <i>TwoDigitHours:</i>
38.305 + * <i>Digit Digit</i></pre>
38.306 + * <i>TwoDigitHours</i> must be between 00 and 23. Other definitions
38.307 + * are as for <a href="#timezone">general time zones</a>.
38.308 + *
38.309 + * <p>For parsing, <a href="#timezone">general time zones</a> are also
38.310 + * accepted.
38.311 + * <li><strong><a name="iso8601timezone">ISO 8601 Time zone:</a></strong>
38.312 + * The number of pattern letters designates the format for both formatting
38.313 + * and parsing as follows:
38.314 + * <pre>
38.315 + * <i>ISO8601TimeZone:</i>
38.316 + * <i>OneLetterISO8601TimeZone</i>
38.317 + * <i>TwoLetterISO8601TimeZone</i>
38.318 + * <i>ThreeLetterISO8601TimeZone</i>
38.319 + * <i>OneLetterISO8601TimeZone:</i>
38.320 + * <i>Sign</i> <i>TwoDigitHours</i>
38.321 + * {@code Z}
38.322 + * <i>TwoLetterISO8601TimeZone:</i>
38.323 + * <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
38.324 + * {@code Z}
38.325 + * <i>ThreeLetterISO8601TimeZone:</i>
38.326 + * <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
38.327 + * {@code Z}</pre>
38.328 + * Other definitions are as for <a href="#timezone">general time zones</a> or
38.329 + * <a href="#rfc822timezone">RFC 822 time zones</a>.
38.330 + *
38.331 + * <p>For formatting, if the offset value from GMT is 0, {@code "Z"} is
38.332 + * produced. If the number of pattern letters is 1, any fraction of an hour
38.333 + * is ignored. For example, if the pattern is {@code "X"} and the time zone is
38.334 + * {@code "GMT+05:30"}, {@code "+05"} is produced.
38.335 + *
38.336 + * <p>For parsing, {@code "Z"} is parsed as the UTC time zone designator.
38.337 + * <a href="#timezone">General time zones</a> are <em>not</em> accepted.
38.338 + *
38.339 + * <p>If the number of pattern letters is 4 or more, {@link
38.340 + * IllegalArgumentException} is thrown when constructing a {@code
38.341 + * SimpleDateFormat} or {@linkplain #applyPattern(String) applying a
38.342 + * pattern}.
38.343 + * </ul>
38.344 + * <code>SimpleDateFormat</code> also supports <em>localized date and time
38.345 + * pattern</em> strings. In these strings, the pattern letters described above
38.346 + * may be replaced with other, locale dependent, pattern letters.
38.347 + * <code>SimpleDateFormat</code> does not deal with the localization of text
38.348 + * other than the pattern letters; that's up to the client of the class.
38.349 + * <p>
38.350 + *
38.351 + * <h4>Examples</h4>
38.352 + *
38.353 + * The following examples show how date and time patterns are interpreted in
38.354 + * the U.S. locale. The given date and time are 2001-07-04 12:08:56 local time
38.355 + * in the U.S. Pacific Time time zone.
38.356 + * <blockquote>
38.357 + * <table border=0 cellspacing=3 cellpadding=0 summary="Examples of date and time patterns interpreted in the U.S. locale">
38.358 + * <tr bgcolor="#ccccff">
38.359 + * <th align=left>Date and Time Pattern
38.360 + * <th align=left>Result
38.361 + * <tr>
38.362 + * <td><code>"yyyy.MM.dd G 'at' HH:mm:ss z"</code>
38.363 + * <td><code>2001.07.04 AD at 12:08:56 PDT</code>
38.364 + * <tr bgcolor="#eeeeff">
38.365 + * <td><code>"EEE, MMM d, ''yy"</code>
38.366 + * <td><code>Wed, Jul 4, '01</code>
38.367 + * <tr>
38.368 + * <td><code>"h:mm a"</code>
38.369 + * <td><code>12:08 PM</code>
38.370 + * <tr bgcolor="#eeeeff">
38.371 + * <td><code>"hh 'o''clock' a, zzzz"</code>
38.372 + * <td><code>12 o'clock PM, Pacific Daylight Time</code>
38.373 + * <tr>
38.374 + * <td><code>"K:mm a, z"</code>
38.375 + * <td><code>0:08 PM, PDT</code>
38.376 + * <tr bgcolor="#eeeeff">
38.377 + * <td><code>"yyyyy.MMMMM.dd GGG hh:mm aaa"</code>
38.378 + * <td><code>02001.July.04 AD 12:08 PM</code>
38.379 + * <tr>
38.380 + * <td><code>"EEE, d MMM yyyy HH:mm:ss Z"</code>
38.381 + * <td><code>Wed, 4 Jul 2001 12:08:56 -0700</code>
38.382 + * <tr bgcolor="#eeeeff">
38.383 + * <td><code>"yyMMddHHmmssZ"</code>
38.384 + * <td><code>010704120856-0700</code>
38.385 + * <tr>
38.386 + * <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
38.387 + * <td><code>2001-07-04T12:08:56.235-0700</code>
38.388 + * <tr bgcolor="#eeeeff">
38.389 + * <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</code>
38.390 + * <td><code>2001-07-04T12:08:56.235-07:00</code>
38.391 + * <tr>
38.392 + * <td><code>"YYYY-'W'ww-u"</code>
38.393 + * <td><code>2001-W27-3</code>
38.394 + * </table>
38.395 + * </blockquote>
38.396 + *
38.397 + * <h4><a name="synchronization">Synchronization</a></h4>
38.398 + *
38.399 + * <p>
38.400 + * Date formats are not synchronized.
38.401 + * It is recommended to create separate format instances for each thread.
38.402 + * If multiple threads access a format concurrently, it must be synchronized
38.403 + * externally.
38.404 + *
38.405 + * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a>
38.406 + * @see java.util.Calendar
38.407 + * @see java.util.TimeZone
38.408 + * @see DateFormat
38.409 + * @see DateFormatSymbols
38.410 + * @author Mark Davis, Chen-Lieh Huang, Alan Liu
38.411 + */
38.412 +public class SimpleDateFormat extends DateFormat {
38.413 +
38.414 + // the official serial version ID which says cryptically
38.415 + // which version we're compatible with
38.416 + static final long serialVersionUID = 4774881970558875024L;
38.417 +
38.418 + // the internal serial version which says which version was written
38.419 + // - 0 (default) for version up to JDK 1.1.3
38.420 + // - 1 for version from JDK 1.1.4, which includes a new field
38.421 + static final int currentSerialVersion = 1;
38.422 +
38.423 + /**
38.424 + * The version of the serialized data on the stream. Possible values:
38.425 + * <ul>
38.426 + * <li><b>0</b> or not present on stream: JDK 1.1.3. This version
38.427 + * has no <code>defaultCenturyStart</code> on stream.
38.428 + * <li><b>1</b> JDK 1.1.4 or later. This version adds
38.429 + * <code>defaultCenturyStart</code>.
38.430 + * </ul>
38.431 + * When streaming out this class, the most recent format
38.432 + * and the highest allowable <code>serialVersionOnStream</code>
38.433 + * is written.
38.434 + * @serial
38.435 + * @since JDK1.1.4
38.436 + */
38.437 + private int serialVersionOnStream = currentSerialVersion;
38.438 +
38.439 + /**
38.440 + * The pattern string of this formatter. This is always a non-localized
38.441 + * pattern. May not be null. See class documentation for details.
38.442 + * @serial
38.443 + */
38.444 + private String pattern;
38.445 +
38.446 + /**
38.447 + * Saved numberFormat and pattern.
38.448 + * @see SimpleDateFormat#checkNegativeNumberExpression
38.449 + */
38.450 + transient private NumberFormat originalNumberFormat;
38.451 + transient private String originalNumberPattern;
38.452 +
38.453 + /**
38.454 + * The minus sign to be used with format and parse.
38.455 + */
38.456 + transient private char minusSign = '-';
38.457 +
38.458 + /**
38.459 + * True when a negative sign follows a number.
38.460 + * (True as default in Arabic.)
38.461 + */
38.462 + transient private boolean hasFollowingMinusSign = false;
38.463 +
38.464 + /**
38.465 + * The compiled pattern.
38.466 + */
38.467 + transient private char[] compiledPattern;
38.468 +
38.469 + /**
38.470 + * Tags for the compiled pattern.
38.471 + */
38.472 + private final static int TAG_QUOTE_ASCII_CHAR = 100;
38.473 + private final static int TAG_QUOTE_CHARS = 101;
38.474 +
38.475 + /**
38.476 + * Locale dependent digit zero.
38.477 + * @see #zeroPaddingNumber
38.478 + * @see java.text.DecimalFormatSymbols#getZeroDigit
38.479 + */
38.480 + transient private char zeroDigit;
38.481 +
38.482 + /**
38.483 + * The symbols used by this formatter for week names, month names,
38.484 + * etc. May not be null.
38.485 + * @serial
38.486 + * @see java.text.DateFormatSymbols
38.487 + */
38.488 + private DateFormatSymbols formatData;
38.489 +
38.490 + /**
38.491 + * We map dates with two-digit years into the century starting at
38.492 + * <code>defaultCenturyStart</code>, which may be any date. May
38.493 + * not be null.
38.494 + * @serial
38.495 + * @since JDK1.1.4
38.496 + */
38.497 + private Date defaultCenturyStart;
38.498 +
38.499 + transient private int defaultCenturyStartYear;
38.500 +
38.501 + private static final int MILLIS_PER_MINUTE = 60 * 1000;
38.502 +
38.503 + // For time zones that have no names, use strings GMT+minutes and
38.504 + // GMT-minutes. For instance, in France the time zone is GMT+60.
38.505 + private static final String GMT = "GMT";
38.506 +
38.507 + /**
38.508 + * Cache to hold the DateTimePatterns of a Locale.
38.509 + */
38.510 + private static final ConcurrentMap<Locale, String[]> cachedLocaleData
38.511 + = new ConcurrentHashMap<Locale, String[]>(3);
38.512 +
38.513 + /**
38.514 + * Cache NumberFormat instances with Locale key.
38.515 + */
38.516 + private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
38.517 + = new ConcurrentHashMap<Locale, NumberFormat>(3);
38.518 +
38.519 + /**
38.520 + * The Locale used to instantiate this
38.521 + * <code>SimpleDateFormat</code>. The value may be null if this object
38.522 + * has been created by an older <code>SimpleDateFormat</code> and
38.523 + * deserialized.
38.524 + *
38.525 + * @serial
38.526 + * @since 1.6
38.527 + */
38.528 + private Locale locale;
38.529 +
38.530 + /**
38.531 + * Indicates whether this <code>SimpleDateFormat</code> should use
38.532 + * the DateFormatSymbols. If true, the format and parse methods
38.533 + * use the DateFormatSymbols values. If false, the format and
38.534 + * parse methods call Calendar.getDisplayName or
38.535 + * Calendar.getDisplayNames.
38.536 + */
38.537 + transient boolean useDateFormatSymbols;
38.538 +
38.539 + /**
38.540 + * Constructs a <code>SimpleDateFormat</code> using the default pattern and
38.541 + * date format symbols for the default locale.
38.542 + * <b>Note:</b> This constructor may not support all locales.
38.543 + * For full coverage, use the factory methods in the {@link DateFormat}
38.544 + * class.
38.545 + */
38.546 + public SimpleDateFormat() {
38.547 + this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT));
38.548 + }
38.549 +
38.550 + /**
38.551 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
38.552 + * the default date format symbols for the default locale.
38.553 + * <b>Note:</b> This constructor may not support all locales.
38.554 + * For full coverage, use the factory methods in the {@link DateFormat}
38.555 + * class.
38.556 + *
38.557 + * @param pattern the pattern describing the date and time format
38.558 + * @exception NullPointerException if the given pattern is null
38.559 + * @exception IllegalArgumentException if the given pattern is invalid
38.560 + */
38.561 + public SimpleDateFormat(String pattern)
38.562 + {
38.563 + this(pattern, Locale.getDefault(Locale.Category.FORMAT));
38.564 + }
38.565 +
38.566 + /**
38.567 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
38.568 + * the default date format symbols for the given locale.
38.569 + * <b>Note:</b> This constructor may not support all locales.
38.570 + * For full coverage, use the factory methods in the {@link DateFormat}
38.571 + * class.
38.572 + *
38.573 + * @param pattern the pattern describing the date and time format
38.574 + * @param locale the locale whose date format symbols should be used
38.575 + * @exception NullPointerException if the given pattern or locale is null
38.576 + * @exception IllegalArgumentException if the given pattern is invalid
38.577 + */
38.578 + public SimpleDateFormat(String pattern, Locale locale)
38.579 + {
38.580 + if (pattern == null || locale == null) {
38.581 + throw new NullPointerException();
38.582 + }
38.583 +
38.584 + initializeCalendar(locale);
38.585 + this.pattern = pattern;
38.586 + this.formatData = DateFormatSymbols.getInstanceRef(locale);
38.587 + this.locale = locale;
38.588 + initialize(locale);
38.589 + }
38.590 +
38.591 + /**
38.592 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
38.593 + * date format symbols.
38.594 + *
38.595 + * @param pattern the pattern describing the date and time format
38.596 + * @param formatSymbols the date format symbols to be used for formatting
38.597 + * @exception NullPointerException if the given pattern or formatSymbols is null
38.598 + * @exception IllegalArgumentException if the given pattern is invalid
38.599 + */
38.600 + public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
38.601 + {
38.602 + if (pattern == null || formatSymbols == null) {
38.603 + throw new NullPointerException();
38.604 + }
38.605 +
38.606 + this.pattern = pattern;
38.607 + this.formatData = (DateFormatSymbols) formatSymbols.clone();
38.608 + this.locale = Locale.getDefault(Locale.Category.FORMAT);
38.609 + initializeCalendar(this.locale);
38.610 + initialize(this.locale);
38.611 + useDateFormatSymbols = true;
38.612 + }
38.613 +
38.614 + /* Package-private, called by DateFormat factory methods */
38.615 + SimpleDateFormat(int timeStyle, int dateStyle, Locale loc) {
38.616 + if (loc == null) {
38.617 + throw new NullPointerException();
38.618 + }
38.619 +
38.620 + this.locale = loc;
38.621 + // initialize calendar and related fields
38.622 + initializeCalendar(loc);
38.623 +
38.624 + /* try the cache first */
38.625 + String[] dateTimePatterns = cachedLocaleData.get(loc);
38.626 + if (dateTimePatterns == null) { /* cache miss */
38.627 + ResourceBundle r = LocaleData.getDateFormatData(loc);
38.628 + if (!isGregorianCalendar()) {
38.629 + try {
38.630 + dateTimePatterns = r.getStringArray(getCalendarName() + ".DateTimePatterns");
38.631 + } catch (MissingResourceException e) {
38.632 + }
38.633 + }
38.634 + if (dateTimePatterns == null) {
38.635 + dateTimePatterns = r.getStringArray("DateTimePatterns");
38.636 + }
38.637 + /* update cache */
38.638 + cachedLocaleData.putIfAbsent(loc, dateTimePatterns);
38.639 + }
38.640 + formatData = DateFormatSymbols.getInstanceRef(loc);
38.641 + if ((timeStyle >= 0) && (dateStyle >= 0)) {
38.642 + Object[] dateTimeArgs = {dateTimePatterns[timeStyle],
38.643 + dateTimePatterns[dateStyle + 4]};
38.644 + pattern = MessageFormat.format(dateTimePatterns[8], dateTimeArgs);
38.645 + }
38.646 + else if (timeStyle >= 0) {
38.647 + pattern = dateTimePatterns[timeStyle];
38.648 + }
38.649 + else if (dateStyle >= 0) {
38.650 + pattern = dateTimePatterns[dateStyle + 4];
38.651 + }
38.652 + else {
38.653 + throw new IllegalArgumentException("No date or time style specified");
38.654 + }
38.655 +
38.656 + initialize(loc);
38.657 + }
38.658 +
38.659 + /* Initialize compiledPattern and numberFormat fields */
38.660 + private void initialize(Locale loc) {
38.661 + // Verify and compile the given pattern.
38.662 + compiledPattern = compile(pattern);
38.663 +
38.664 + /* try the cache first */
38.665 + numberFormat = cachedNumberFormatData.get(loc);
38.666 + if (numberFormat == null) { /* cache miss */
38.667 + numberFormat = NumberFormat.getIntegerInstance(loc);
38.668 + numberFormat.setGroupingUsed(false);
38.669 +
38.670 + /* update cache */
38.671 + cachedNumberFormatData.putIfAbsent(loc, numberFormat);
38.672 + }
38.673 + numberFormat = (NumberFormat) numberFormat.clone();
38.674 +
38.675 + initializeDefaultCentury();
38.676 + }
38.677 +
38.678 + private void initializeCalendar(Locale loc) {
38.679 + if (calendar == null) {
38.680 + assert loc != null;
38.681 + // The format object must be constructed using the symbols for this zone.
38.682 + // However, the calendar should use the current default TimeZone.
38.683 + // If this is not contained in the locale zone strings, then the zone
38.684 + // will be formatted using generic GMT+/-H:MM nomenclature.
38.685 + calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
38.686 + }
38.687 + }
38.688 +
38.689 + /**
38.690 + * Returns the compiled form of the given pattern. The syntax of
38.691 + * the compiled pattern is:
38.692 + * <blockquote>
38.693 + * CompiledPattern:
38.694 + * EntryList
38.695 + * EntryList:
38.696 + * Entry
38.697 + * EntryList Entry
38.698 + * Entry:
38.699 + * TagField
38.700 + * TagField data
38.701 + * TagField:
38.702 + * Tag Length
38.703 + * TaggedData
38.704 + * Tag:
38.705 + * pattern_char_index
38.706 + * TAG_QUOTE_CHARS
38.707 + * Length:
38.708 + * short_length
38.709 + * long_length
38.710 + * TaggedData:
38.711 + * TAG_QUOTE_ASCII_CHAR ascii_char
38.712 + *
38.713 + * </blockquote>
38.714 + *
38.715 + * where `short_length' is an 8-bit unsigned integer between 0 and
38.716 + * 254. `long_length' is a sequence of an 8-bit integer 255 and a
38.717 + * 32-bit signed integer value which is split into upper and lower
38.718 + * 16-bit fields in two char's. `pattern_char_index' is an 8-bit
38.719 + * integer between 0 and 18. `ascii_char' is an 7-bit ASCII
38.720 + * character value. `data' depends on its Tag value.
38.721 + * <p>
38.722 + * If Length is short_length, Tag and short_length are packed in a
38.723 + * single char, as illustrated below.
38.724 + * <blockquote>
38.725 + * char[0] = (Tag << 8) | short_length;
38.726 + * </blockquote>
38.727 + *
38.728 + * If Length is long_length, Tag and 255 are packed in the first
38.729 + * char and a 32-bit integer, as illustrated below.
38.730 + * <blockquote>
38.731 + * char[0] = (Tag << 8) | 255;
38.732 + * char[1] = (char) (long_length >>> 16);
38.733 + * char[2] = (char) (long_length & 0xffff);
38.734 + * </blockquote>
38.735 + * <p>
38.736 + * If Tag is a pattern_char_index, its Length is the number of
38.737 + * pattern characters. For example, if the given pattern is
38.738 + * "yyyy", Tag is 1 and Length is 4, followed by no data.
38.739 + * <p>
38.740 + * If Tag is TAG_QUOTE_CHARS, its Length is the number of char's
38.741 + * following the TagField. For example, if the given pattern is
38.742 + * "'o''clock'", Length is 7 followed by a char sequence of
38.743 + * <code>o&nbs;'&nbs;c&nbs;l&nbs;o&nbs;c&nbs;k</code>.
38.744 + * <p>
38.745 + * TAG_QUOTE_ASCII_CHAR is a special tag and has an ASCII
38.746 + * character in place of Length. For example, if the given pattern
38.747 + * is "'o'", the TaggedData entry is
38.748 + * <code>((TAG_QUOTE_ASCII_CHAR&nbs;<<&nbs;8)&nbs;|&nbs;'o')</code>.
38.749 + *
38.750 + * @exception NullPointerException if the given pattern is null
38.751 + * @exception IllegalArgumentException if the given pattern is invalid
38.752 + */
38.753 + private char[] compile(String pattern) {
38.754 + int length = pattern.length();
38.755 + boolean inQuote = false;
38.756 + StringBuilder compiledPattern = new StringBuilder(length * 2);
38.757 + StringBuilder tmpBuffer = null;
38.758 + int count = 0;
38.759 + int lastTag = -1;
38.760 +
38.761 + for (int i = 0; i < length; i++) {
38.762 + char c = pattern.charAt(i);
38.763 +
38.764 + if (c == '\'') {
38.765 + // '' is treated as a single quote regardless of being
38.766 + // in a quoted section.
38.767 + if ((i + 1) < length) {
38.768 + c = pattern.charAt(i + 1);
38.769 + if (c == '\'') {
38.770 + i++;
38.771 + if (count != 0) {
38.772 + encode(lastTag, count, compiledPattern);
38.773 + lastTag = -1;
38.774 + count = 0;
38.775 + }
38.776 + if (inQuote) {
38.777 + tmpBuffer.append(c);
38.778 + } else {
38.779 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
38.780 + }
38.781 + continue;
38.782 + }
38.783 + }
38.784 + if (!inQuote) {
38.785 + if (count != 0) {
38.786 + encode(lastTag, count, compiledPattern);
38.787 + lastTag = -1;
38.788 + count = 0;
38.789 + }
38.790 + if (tmpBuffer == null) {
38.791 + tmpBuffer = new StringBuilder(length);
38.792 + } else {
38.793 + tmpBuffer.setLength(0);
38.794 + }
38.795 + inQuote = true;
38.796 + } else {
38.797 + int len = tmpBuffer.length();
38.798 + if (len == 1) {
38.799 + char ch = tmpBuffer.charAt(0);
38.800 + if (ch < 128) {
38.801 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch));
38.802 + } else {
38.803 + compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | 1));
38.804 + compiledPattern.append(ch);
38.805 + }
38.806 + } else {
38.807 + encode(TAG_QUOTE_CHARS, len, compiledPattern);
38.808 + compiledPattern.append(tmpBuffer);
38.809 + }
38.810 + inQuote = false;
38.811 + }
38.812 + continue;
38.813 + }
38.814 + if (inQuote) {
38.815 + tmpBuffer.append(c);
38.816 + continue;
38.817 + }
38.818 + if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
38.819 + if (count != 0) {
38.820 + encode(lastTag, count, compiledPattern);
38.821 + lastTag = -1;
38.822 + count = 0;
38.823 + }
38.824 + if (c < 128) {
38.825 + // In most cases, c would be a delimiter, such as ':'.
38.826 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
38.827 + } else {
38.828 + // Take any contiguous non-ASCII alphabet characters and
38.829 + // put them in a single TAG_QUOTE_CHARS.
38.830 + int j;
38.831 + for (j = i + 1; j < length; j++) {
38.832 + char d = pattern.charAt(j);
38.833 + if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) {
38.834 + break;
38.835 + }
38.836 + }
38.837 + compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | (j - i)));
38.838 + for (; i < j; i++) {
38.839 + compiledPattern.append(pattern.charAt(i));
38.840 + }
38.841 + i--;
38.842 + }
38.843 + continue;
38.844 + }
38.845 +
38.846 + int tag;
38.847 + if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
38.848 + throw new IllegalArgumentException("Illegal pattern character " +
38.849 + "'" + c + "'");
38.850 + }
38.851 + if (lastTag == -1 || lastTag == tag) {
38.852 + lastTag = tag;
38.853 + count++;
38.854 + continue;
38.855 + }
38.856 + encode(lastTag, count, compiledPattern);
38.857 + lastTag = tag;
38.858 + count = 1;
38.859 + }
38.860 +
38.861 + if (inQuote) {
38.862 + throw new IllegalArgumentException("Unterminated quote");
38.863 + }
38.864 +
38.865 + if (count != 0) {
38.866 + encode(lastTag, count, compiledPattern);
38.867 + }
38.868 +
38.869 + // Copy the compiled pattern to a char array
38.870 + int len = compiledPattern.length();
38.871 + char[] r = new char[len];
38.872 + compiledPattern.getChars(0, len, r, 0);
38.873 + return r;
38.874 + }
38.875 +
38.876 + /**
38.877 + * Encodes the given tag and length and puts encoded char(s) into buffer.
38.878 + */
38.879 + private static final void encode(int tag, int length, StringBuilder buffer) {
38.880 + if (tag == PATTERN_ISO_ZONE && length >= 4) {
38.881 + throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length);
38.882 + }
38.883 + if (length < 255) {
38.884 + buffer.append((char)(tag << 8 | length));
38.885 + } else {
38.886 + buffer.append((char)((tag << 8) | 0xff));
38.887 + buffer.append((char)(length >>> 16));
38.888 + buffer.append((char)(length & 0xffff));
38.889 + }
38.890 + }
38.891 +
38.892 + /* Initialize the fields we use to disambiguate ambiguous years. Separate
38.893 + * so we can call it from readObject().
38.894 + */
38.895 + private void initializeDefaultCentury() {
38.896 + calendar.setTimeInMillis(System.currentTimeMillis());
38.897 + calendar.add( Calendar.YEAR, -80 );
38.898 + parseAmbiguousDatesAsAfter(calendar.getTime());
38.899 + }
38.900 +
38.901 + /* Define one-century window into which to disambiguate dates using
38.902 + * two-digit years.
38.903 + */
38.904 + private void parseAmbiguousDatesAsAfter(Date startDate) {
38.905 + defaultCenturyStart = startDate;
38.906 + calendar.setTime(startDate);
38.907 + defaultCenturyStartYear = calendar.get(Calendar.YEAR);
38.908 + }
38.909 +
38.910 + /**
38.911 + * Sets the 100-year period 2-digit years will be interpreted as being in
38.912 + * to begin on the date the user specifies.
38.913 + *
38.914 + * @param startDate During parsing, two digit years will be placed in the range
38.915 + * <code>startDate</code> to <code>startDate + 100 years</code>.
38.916 + * @see #get2DigitYearStart
38.917 + * @since 1.2
38.918 + */
38.919 + public void set2DigitYearStart(Date startDate) {
38.920 + parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
38.921 + }
38.922 +
38.923 + /**
38.924 + * Returns the beginning date of the 100-year period 2-digit years are interpreted
38.925 + * as being within.
38.926 + *
38.927 + * @return the start of the 100-year period into which two digit years are
38.928 + * parsed
38.929 + * @see #set2DigitYearStart
38.930 + * @since 1.2
38.931 + */
38.932 + public Date get2DigitYearStart() {
38.933 + return (Date) defaultCenturyStart.clone();
38.934 + }
38.935 +
38.936 + /**
38.937 + * Formats the given <code>Date</code> into a date/time string and appends
38.938 + * the result to the given <code>StringBuffer</code>.
38.939 + *
38.940 + * @param date the date-time value to be formatted into a date-time string.
38.941 + * @param toAppendTo where the new date-time text is to be appended.
38.942 + * @param pos the formatting position. On input: an alignment field,
38.943 + * if desired. On output: the offsets of the alignment field.
38.944 + * @return the formatted date-time string.
38.945 + * @exception NullPointerException if the given {@code date} is {@code null}.
38.946 + */
38.947 + public StringBuffer format(Date date, StringBuffer toAppendTo,
38.948 + FieldPosition pos)
38.949 + {
38.950 + pos.beginIndex = pos.endIndex = 0;
38.951 + return format(date, toAppendTo, pos.getFieldDelegate());
38.952 + }
38.953 +
38.954 + // Called from Format after creating a FieldDelegate
38.955 + private StringBuffer format(Date date, StringBuffer toAppendTo,
38.956 + FieldDelegate delegate) {
38.957 + // Convert input date to time field list
38.958 + calendar.setTime(date);
38.959 +
38.960 + boolean useDateFormatSymbols = useDateFormatSymbols();
38.961 +
38.962 + for (int i = 0; i < compiledPattern.length; ) {
38.963 + int tag = compiledPattern[i] >>> 8;
38.964 + int count = compiledPattern[i++] & 0xff;
38.965 + if (count == 255) {
38.966 + count = compiledPattern[i++] << 16;
38.967 + count |= compiledPattern[i++];
38.968 + }
38.969 +
38.970 + switch (tag) {
38.971 + case TAG_QUOTE_ASCII_CHAR:
38.972 + toAppendTo.append((char)count);
38.973 + break;
38.974 +
38.975 + case TAG_QUOTE_CHARS:
38.976 + toAppendTo.append(compiledPattern, i, count);
38.977 + i += count;
38.978 + break;
38.979 +
38.980 + default:
38.981 + subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
38.982 + break;
38.983 + }
38.984 + }
38.985 + return toAppendTo;
38.986 + }
38.987 +
38.988 + /**
38.989 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
38.990 + * You can use the returned <code>AttributedCharacterIterator</code>
38.991 + * to build the resulting String, as well as to determine information
38.992 + * about the resulting String.
38.993 + * <p>
38.994 + * Each attribute key of the AttributedCharacterIterator will be of type
38.995 + * <code>DateFormat.Field</code>, with the corresponding attribute value
38.996 + * being the same as the attribute key.
38.997 + *
38.998 + * @exception NullPointerException if obj is null.
38.999 + * @exception IllegalArgumentException if the Format cannot format the
38.1000 + * given object, or if the Format's pattern string is invalid.
38.1001 + * @param obj The object to format
38.1002 + * @return AttributedCharacterIterator describing the formatted value.
38.1003 + * @since 1.4
38.1004 + */
38.1005 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
38.1006 + StringBuffer sb = new StringBuffer();
38.1007 + CharacterIteratorFieldDelegate delegate = new
38.1008 + CharacterIteratorFieldDelegate();
38.1009 +
38.1010 + if (obj instanceof Date) {
38.1011 + format((Date)obj, sb, delegate);
38.1012 + }
38.1013 + else if (obj instanceof Number) {
38.1014 + format(new Date(((Number)obj).longValue()), sb, delegate);
38.1015 + }
38.1016 + else if (obj == null) {
38.1017 + throw new NullPointerException(
38.1018 + "formatToCharacterIterator must be passed non-null object");
38.1019 + }
38.1020 + else {
38.1021 + throw new IllegalArgumentException(
38.1022 + "Cannot format given Object as a Date");
38.1023 + }
38.1024 + return delegate.getIterator(sb.toString());
38.1025 + }
38.1026 +
38.1027 + // Map index into pattern character string to Calendar field number
38.1028 + private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD =
38.1029 + {
38.1030 + Calendar.ERA, Calendar.YEAR, Calendar.MONTH, Calendar.DATE,
38.1031 + Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY, Calendar.MINUTE,
38.1032 + Calendar.SECOND, Calendar.MILLISECOND, Calendar.DAY_OF_WEEK,
38.1033 + Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
38.1034 + Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH,
38.1035 + Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
38.1036 + Calendar.ZONE_OFFSET,
38.1037 + // Pseudo Calendar fields
38.1038 + CalendarBuilder.WEEK_YEAR,
38.1039 + CalendarBuilder.ISO_DAY_OF_WEEK,
38.1040 + Calendar.ZONE_OFFSET
38.1041 + };
38.1042 +
38.1043 + // Map index into pattern character string to DateFormat field number
38.1044 + private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
38.1045 + DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD,
38.1046 + DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD,
38.1047 + DateFormat.HOUR_OF_DAY0_FIELD, DateFormat.MINUTE_FIELD,
38.1048 + DateFormat.SECOND_FIELD, DateFormat.MILLISECOND_FIELD,
38.1049 + DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD,
38.1050 + DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, DateFormat.WEEK_OF_YEAR_FIELD,
38.1051 + DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
38.1052 + DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD,
38.1053 + DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD,
38.1054 + DateFormat.YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD,
38.1055 + DateFormat.TIMEZONE_FIELD
38.1056 + };
38.1057 +
38.1058 + // Maps from DecimalFormatSymbols index to Field constant
38.1059 + private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = {
38.1060 + Field.ERA, Field.YEAR, Field.MONTH, Field.DAY_OF_MONTH,
38.1061 + Field.HOUR_OF_DAY1, Field.HOUR_OF_DAY0, Field.MINUTE,
38.1062 + Field.SECOND, Field.MILLISECOND, Field.DAY_OF_WEEK,
38.1063 + Field.DAY_OF_YEAR, Field.DAY_OF_WEEK_IN_MONTH,
38.1064 + Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH,
38.1065 + Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE,
38.1066 + Field.TIME_ZONE,
38.1067 + Field.YEAR, Field.DAY_OF_WEEK,
38.1068 + Field.TIME_ZONE
38.1069 + };
38.1070 +
38.1071 + /**
38.1072 + * Private member function that does the real date/time formatting.
38.1073 + */
38.1074 + private void subFormat(int patternCharIndex, int count,
38.1075 + FieldDelegate delegate, StringBuffer buffer,
38.1076 + boolean useDateFormatSymbols)
38.1077 + {
38.1078 + int maxIntCount = Integer.MAX_VALUE;
38.1079 + String current = null;
38.1080 + int beginOffset = buffer.length();
38.1081 +
38.1082 + int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
38.1083 + int value;
38.1084 + if (field == CalendarBuilder.WEEK_YEAR) {
38.1085 + if (calendar.isWeekDateSupported()) {
38.1086 + value = calendar.getWeekYear();
38.1087 + } else {
38.1088 + // use calendar year 'y' instead
38.1089 + patternCharIndex = PATTERN_YEAR;
38.1090 + field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
38.1091 + value = calendar.get(field);
38.1092 + }
38.1093 + } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
38.1094 + value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
38.1095 + } else {
38.1096 + value = calendar.get(field);
38.1097 + }
38.1098 +
38.1099 + int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
38.1100 + if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
38.1101 + current = calendar.getDisplayName(field, style, locale);
38.1102 + }
38.1103 +
38.1104 + // Note: zeroPaddingNumber() assumes that maxDigits is either
38.1105 + // 2 or maxIntCount. If we make any changes to this,
38.1106 + // zeroPaddingNumber() must be fixed.
38.1107 +
38.1108 + switch (patternCharIndex) {
38.1109 + case PATTERN_ERA: // 'G'
38.1110 + if (useDateFormatSymbols) {
38.1111 + String[] eras = formatData.getEras();
38.1112 + if (value < eras.length)
38.1113 + current = eras[value];
38.1114 + }
38.1115 + if (current == null)
38.1116 + current = "";
38.1117 + break;
38.1118 +
38.1119 + case PATTERN_WEEK_YEAR: // 'Y'
38.1120 + case PATTERN_YEAR: // 'y'
38.1121 + if (calendar instanceof GregorianCalendar) {
38.1122 + if (count != 2)
38.1123 + zeroPaddingNumber(value, count, maxIntCount, buffer);
38.1124 + else // count == 2
38.1125 + zeroPaddingNumber(value, 2, 2, buffer); // clip 1996 to 96
38.1126 + } else {
38.1127 + if (current == null) {
38.1128 + zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
38.1129 + maxIntCount, buffer);
38.1130 + }
38.1131 + }
38.1132 + break;
38.1133 +
38.1134 + case PATTERN_MONTH: // 'M'
38.1135 + if (useDateFormatSymbols) {
38.1136 + String[] months;
38.1137 + if (count >= 4) {
38.1138 + months = formatData.getMonths();
38.1139 + current = months[value];
38.1140 + } else if (count == 3) {
38.1141 + months = formatData.getShortMonths();
38.1142 + current = months[value];
38.1143 + }
38.1144 + } else {
38.1145 + if (count < 3) {
38.1146 + current = null;
38.1147 + }
38.1148 + }
38.1149 + if (current == null) {
38.1150 + zeroPaddingNumber(value+1, count, maxIntCount, buffer);
38.1151 + }
38.1152 + break;
38.1153 +
38.1154 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
38.1155 + if (current == null) {
38.1156 + if (value == 0)
38.1157 + zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1,
38.1158 + count, maxIntCount, buffer);
38.1159 + else
38.1160 + zeroPaddingNumber(value, count, maxIntCount, buffer);
38.1161 + }
38.1162 + break;
38.1163 +
38.1164 + case PATTERN_DAY_OF_WEEK: // 'E'
38.1165 + if (useDateFormatSymbols) {
38.1166 + String[] weekdays;
38.1167 + if (count >= 4) {
38.1168 + weekdays = formatData.getWeekdays();
38.1169 + current = weekdays[value];
38.1170 + } else { // count < 4, use abbreviated form if exists
38.1171 + weekdays = formatData.getShortWeekdays();
38.1172 + current = weekdays[value];
38.1173 + }
38.1174 + }
38.1175 + break;
38.1176 +
38.1177 + case PATTERN_AM_PM: // 'a'
38.1178 + if (useDateFormatSymbols) {
38.1179 + String[] ampm = formatData.getAmPmStrings();
38.1180 + current = ampm[value];
38.1181 + }
38.1182 + break;
38.1183 +
38.1184 + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
38.1185 + if (current == null) {
38.1186 + if (value == 0)
38.1187 + zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1,
38.1188 + count, maxIntCount, buffer);
38.1189 + else
38.1190 + zeroPaddingNumber(value, count, maxIntCount, buffer);
38.1191 + }
38.1192 + break;
38.1193 +
38.1194 + case PATTERN_ZONE_NAME: // 'z'
38.1195 + if (current == null) {
38.1196 + if (formatData.locale == null || formatData.isZoneStringsSet) {
38.1197 + int zoneIndex =
38.1198 + formatData.getZoneIndex(calendar.getTimeZone().getID());
38.1199 + if (zoneIndex == -1) {
38.1200 + value = calendar.get(Calendar.ZONE_OFFSET) +
38.1201 + calendar.get(Calendar.DST_OFFSET);
38.1202 + buffer.append(ZoneInfoFile.toCustomID(value));
38.1203 + } else {
38.1204 + int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3;
38.1205 + if (count < 4) {
38.1206 + // Use the short name
38.1207 + index++;
38.1208 + }
38.1209 + String[][] zoneStrings = formatData.getZoneStringsWrapper();
38.1210 + buffer.append(zoneStrings[zoneIndex][index]);
38.1211 + }
38.1212 + } else {
38.1213 + TimeZone tz = calendar.getTimeZone();
38.1214 + boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
38.1215 + int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
38.1216 + buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale));
38.1217 + }
38.1218 + }
38.1219 + break;
38.1220 +
38.1221 + case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
38.1222 + value = (calendar.get(Calendar.ZONE_OFFSET) +
38.1223 + calendar.get(Calendar.DST_OFFSET)) / 60000;
38.1224 +
38.1225 + int width = 4;
38.1226 + if (value >= 0) {
38.1227 + buffer.append('+');
38.1228 + } else {
38.1229 + width++;
38.1230 + }
38.1231 +
38.1232 + int num = (value / 60) * 100 + (value % 60);
38.1233 + CalendarUtils.sprintf0d(buffer, num, width);
38.1234 + break;
38.1235 +
38.1236 + case PATTERN_ISO_ZONE: // 'X'
38.1237 + value = calendar.get(Calendar.ZONE_OFFSET)
38.1238 + + calendar.get(Calendar.DST_OFFSET);
38.1239 +
38.1240 + if (value == 0) {
38.1241 + buffer.append('Z');
38.1242 + break;
38.1243 + }
38.1244 +
38.1245 + value /= 60000;
38.1246 + if (value >= 0) {
38.1247 + buffer.append('+');
38.1248 + } else {
38.1249 + buffer.append('-');
38.1250 + value = -value;
38.1251 + }
38.1252 +
38.1253 + CalendarUtils.sprintf0d(buffer, value / 60, 2);
38.1254 + if (count == 1) {
38.1255 + break;
38.1256 + }
38.1257 +
38.1258 + if (count == 3) {
38.1259 + buffer.append(':');
38.1260 + }
38.1261 + CalendarUtils.sprintf0d(buffer, value % 60, 2);
38.1262 + break;
38.1263 +
38.1264 + default:
38.1265 + // case PATTERN_DAY_OF_MONTH: // 'd'
38.1266 + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
38.1267 + // case PATTERN_MINUTE: // 'm'
38.1268 + // case PATTERN_SECOND: // 's'
38.1269 + // case PATTERN_MILLISECOND: // 'S'
38.1270 + // case PATTERN_DAY_OF_YEAR: // 'D'
38.1271 + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
38.1272 + // case PATTERN_WEEK_OF_YEAR: // 'w'
38.1273 + // case PATTERN_WEEK_OF_MONTH: // 'W'
38.1274 + // case PATTERN_HOUR0: // 'K' eg, 11PM + 1 hour =>> 0 AM
38.1275 + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' pseudo field, Monday = 1, ..., Sunday = 7
38.1276 + if (current == null) {
38.1277 + zeroPaddingNumber(value, count, maxIntCount, buffer);
38.1278 + }
38.1279 + break;
38.1280 + } // switch (patternCharIndex)
38.1281 +
38.1282 + if (current != null) {
38.1283 + buffer.append(current);
38.1284 + }
38.1285 +
38.1286 + int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex];
38.1287 + Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex];
38.1288 +
38.1289 + delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer);
38.1290 + }
38.1291 +
38.1292 + /**
38.1293 + * Formats a number with the specified minimum and maximum number of digits.
38.1294 + */
38.1295 + private final void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer)
38.1296 + {
38.1297 + // Optimization for 1, 2 and 4 digit numbers. This should
38.1298 + // cover most cases of formatting date/time related items.
38.1299 + // Note: This optimization code assumes that maxDigits is
38.1300 + // either 2 or Integer.MAX_VALUE (maxIntCount in format()).
38.1301 + try {
38.1302 + if (zeroDigit == 0) {
38.1303 + zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit();
38.1304 + }
38.1305 + if (value >= 0) {
38.1306 + if (value < 100 && minDigits >= 1 && minDigits <= 2) {
38.1307 + if (value < 10) {
38.1308 + if (minDigits == 2) {
38.1309 + buffer.append(zeroDigit);
38.1310 + }
38.1311 + buffer.append((char)(zeroDigit + value));
38.1312 + } else {
38.1313 + buffer.append((char)(zeroDigit + value / 10));
38.1314 + buffer.append((char)(zeroDigit + value % 10));
38.1315 + }
38.1316 + return;
38.1317 + } else if (value >= 1000 && value < 10000) {
38.1318 + if (minDigits == 4) {
38.1319 + buffer.append((char)(zeroDigit + value / 1000));
38.1320 + value %= 1000;
38.1321 + buffer.append((char)(zeroDigit + value / 100));
38.1322 + value %= 100;
38.1323 + buffer.append((char)(zeroDigit + value / 10));
38.1324 + buffer.append((char)(zeroDigit + value % 10));
38.1325 + return;
38.1326 + }
38.1327 + if (minDigits == 2 && maxDigits == 2) {
38.1328 + zeroPaddingNumber(value % 100, 2, 2, buffer);
38.1329 + return;
38.1330 + }
38.1331 + }
38.1332 + }
38.1333 + } catch (Exception e) {
38.1334 + }
38.1335 +
38.1336 + numberFormat.setMinimumIntegerDigits(minDigits);
38.1337 + numberFormat.setMaximumIntegerDigits(maxDigits);
38.1338 + numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE);
38.1339 + }
38.1340 +
38.1341 +
38.1342 + /**
38.1343 + * Parses text from a string to produce a <code>Date</code>.
38.1344 + * <p>
38.1345 + * The method attempts to parse text starting at the index given by
38.1346 + * <code>pos</code>.
38.1347 + * If parsing succeeds, then the index of <code>pos</code> is updated
38.1348 + * to the index after the last character used (parsing does not necessarily
38.1349 + * use all characters up to the end of the string), and the parsed
38.1350 + * date is returned. The updated <code>pos</code> can be used to
38.1351 + * indicate the starting point for the next call to this method.
38.1352 + * If an error occurs, then the index of <code>pos</code> is not
38.1353 + * changed, the error index of <code>pos</code> is set to the index of
38.1354 + * the character where the error occurred, and null is returned.
38.1355 + *
38.1356 + * <p>This parsing operation uses the {@link DateFormat#calendar
38.1357 + * calendar} to produce a {@code Date}. All of the {@code
38.1358 + * calendar}'s date-time fields are {@linkplain Calendar#clear()
38.1359 + * cleared} before parsing, and the {@code calendar}'s default
38.1360 + * values of the date-time fields are used for any missing
38.1361 + * date-time information. For example, the year value of the
38.1362 + * parsed {@code Date} is 1970 with {@link GregorianCalendar} if
38.1363 + * no year value is given from the parsing operation. The {@code
38.1364 + * TimeZone} value may be overwritten, depending on the given
38.1365 + * pattern and the time zone value in {@code text}. Any {@code
38.1366 + * TimeZone} value that has previously been set by a call to
38.1367 + * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
38.1368 + * to be restored for further operations.
38.1369 + *
38.1370 + * @param text A <code>String</code>, part of which should be parsed.
38.1371 + * @param pos A <code>ParsePosition</code> object with index and error
38.1372 + * index information as described above.
38.1373 + * @return A <code>Date</code> parsed from the string. In case of
38.1374 + * error, returns null.
38.1375 + * @exception NullPointerException if <code>text</code> or <code>pos</code> is null.
38.1376 + */
38.1377 + public Date parse(String text, ParsePosition pos)
38.1378 + {
38.1379 + checkNegativeNumberExpression();
38.1380 +
38.1381 + int start = pos.index;
38.1382 + int oldStart = start;
38.1383 + int textLength = text.length();
38.1384 +
38.1385 + boolean[] ambiguousYear = {false};
38.1386 +
38.1387 + CalendarBuilder calb = new CalendarBuilder();
38.1388 +
38.1389 + for (int i = 0; i < compiledPattern.length; ) {
38.1390 + int tag = compiledPattern[i] >>> 8;
38.1391 + int count = compiledPattern[i++] & 0xff;
38.1392 + if (count == 255) {
38.1393 + count = compiledPattern[i++] << 16;
38.1394 + count |= compiledPattern[i++];
38.1395 + }
38.1396 +
38.1397 + switch (tag) {
38.1398 + case TAG_QUOTE_ASCII_CHAR:
38.1399 + if (start >= textLength || text.charAt(start) != (char)count) {
38.1400 + pos.index = oldStart;
38.1401 + pos.errorIndex = start;
38.1402 + return null;
38.1403 + }
38.1404 + start++;
38.1405 + break;
38.1406 +
38.1407 + case TAG_QUOTE_CHARS:
38.1408 + while (count-- > 0) {
38.1409 + if (start >= textLength || text.charAt(start) != compiledPattern[i++]) {
38.1410 + pos.index = oldStart;
38.1411 + pos.errorIndex = start;
38.1412 + return null;
38.1413 + }
38.1414 + start++;
38.1415 + }
38.1416 + break;
38.1417 +
38.1418 + default:
38.1419 + // Peek the next pattern to determine if we need to
38.1420 + // obey the number of pattern letters for
38.1421 + // parsing. It's required when parsing contiguous
38.1422 + // digit text (e.g., "20010704") with a pattern which
38.1423 + // has no delimiters between fields, like "yyyyMMdd".
38.1424 + boolean obeyCount = false;
38.1425 +
38.1426 + // In Arabic, a minus sign for a negative number is put after
38.1427 + // the number. Even in another locale, a minus sign can be
38.1428 + // put after a number using DateFormat.setNumberFormat().
38.1429 + // If both the minus sign and the field-delimiter are '-',
38.1430 + // subParse() needs to determine whether a '-' after a number
38.1431 + // in the given text is a delimiter or is a minus sign for the
38.1432 + // preceding number. We give subParse() a clue based on the
38.1433 + // information in compiledPattern.
38.1434 + boolean useFollowingMinusSignAsDelimiter = false;
38.1435 +
38.1436 + if (i < compiledPattern.length) {
38.1437 + int nextTag = compiledPattern[i] >>> 8;
38.1438 + if (!(nextTag == TAG_QUOTE_ASCII_CHAR ||
38.1439 + nextTag == TAG_QUOTE_CHARS)) {
38.1440 + obeyCount = true;
38.1441 + }
38.1442 +
38.1443 + if (hasFollowingMinusSign &&
38.1444 + (nextTag == TAG_QUOTE_ASCII_CHAR ||
38.1445 + nextTag == TAG_QUOTE_CHARS)) {
38.1446 + int c;
38.1447 + if (nextTag == TAG_QUOTE_ASCII_CHAR) {
38.1448 + c = compiledPattern[i] & 0xff;
38.1449 + } else {
38.1450 + c = compiledPattern[i+1];
38.1451 + }
38.1452 +
38.1453 + if (c == minusSign) {
38.1454 + useFollowingMinusSignAsDelimiter = true;
38.1455 + }
38.1456 + }
38.1457 + }
38.1458 + start = subParse(text, start, tag, count, obeyCount,
38.1459 + ambiguousYear, pos,
38.1460 + useFollowingMinusSignAsDelimiter, calb);
38.1461 + if (start < 0) {
38.1462 + pos.index = oldStart;
38.1463 + return null;
38.1464 + }
38.1465 + }
38.1466 + }
38.1467 +
38.1468 + // At this point the fields of Calendar have been set. Calendar
38.1469 + // will fill in default values for missing fields when the time
38.1470 + // is computed.
38.1471 +
38.1472 + pos.index = start;
38.1473 +
38.1474 + Date parsedDate;
38.1475 + try {
38.1476 + parsedDate = calb.establish(calendar).getTime();
38.1477 + // If the year value is ambiguous,
38.1478 + // then the two-digit year == the default start year
38.1479 + if (ambiguousYear[0]) {
38.1480 + if (parsedDate.before(defaultCenturyStart)) {
38.1481 + parsedDate = calb.addYear(100).establish(calendar).getTime();
38.1482 + }
38.1483 + }
38.1484 + }
38.1485 + // An IllegalArgumentException will be thrown by Calendar.getTime()
38.1486 + // if any fields are out of range, e.g., MONTH == 17.
38.1487 + catch (IllegalArgumentException e) {
38.1488 + pos.errorIndex = start;
38.1489 + pos.index = oldStart;
38.1490 + return null;
38.1491 + }
38.1492 +
38.1493 + return parsedDate;
38.1494 + }
38.1495 +
38.1496 + /**
38.1497 + * Private code-size reduction function used by subParse.
38.1498 + * @param text the time text being parsed.
38.1499 + * @param start where to start parsing.
38.1500 + * @param field the date field being parsed.
38.1501 + * @param data the string array to parsed.
38.1502 + * @return the new start position if matching succeeded; a negative number
38.1503 + * indicating matching failure, otherwise.
38.1504 + */
38.1505 + private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
38.1506 + {
38.1507 + int i = 0;
38.1508 + int count = data.length;
38.1509 +
38.1510 + if (field == Calendar.DAY_OF_WEEK) i = 1;
38.1511 +
38.1512 + // There may be multiple strings in the data[] array which begin with
38.1513 + // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
38.1514 + // We keep track of the longest match, and return that. Note that this
38.1515 + // unfortunately requires us to test all array elements.
38.1516 + int bestMatchLength = 0, bestMatch = -1;
38.1517 + for (; i<count; ++i)
38.1518 + {
38.1519 + int length = data[i].length();
38.1520 + // Always compare if we have no match yet; otherwise only compare
38.1521 + // against potentially better matches (longer strings).
38.1522 + if (length > bestMatchLength &&
38.1523 + text.regionMatches(true, start, data[i], 0, length))
38.1524 + {
38.1525 + bestMatch = i;
38.1526 + bestMatchLength = length;
38.1527 + }
38.1528 + }
38.1529 + if (bestMatch >= 0)
38.1530 + {
38.1531 + calb.set(field, bestMatch);
38.1532 + return start + bestMatchLength;
38.1533 + }
38.1534 + return -start;
38.1535 + }
38.1536 +
38.1537 + /**
38.1538 + * Performs the same thing as matchString(String, int, int,
38.1539 + * String[]). This method takes a Map<String, Integer> instead of
38.1540 + * String[].
38.1541 + */
38.1542 + private int matchString(String text, int start, int field,
38.1543 + Map<String,Integer> data, CalendarBuilder calb) {
38.1544 + if (data != null) {
38.1545 + String bestMatch = null;
38.1546 +
38.1547 + for (String name : data.keySet()) {
38.1548 + int length = name.length();
38.1549 + if (bestMatch == null || length > bestMatch.length()) {
38.1550 + if (text.regionMatches(true, start, name, 0, length)) {
38.1551 + bestMatch = name;
38.1552 + }
38.1553 + }
38.1554 + }
38.1555 +
38.1556 + if (bestMatch != null) {
38.1557 + calb.set(field, data.get(bestMatch));
38.1558 + return start + bestMatch.length();
38.1559 + }
38.1560 + }
38.1561 + return -start;
38.1562 + }
38.1563 +
38.1564 + private int matchZoneString(String text, int start, String[] zoneNames) {
38.1565 + for (int i = 1; i <= 4; ++i) {
38.1566 + // Checking long and short zones [1 & 2],
38.1567 + // and long and short daylight [3 & 4].
38.1568 + String zoneName = zoneNames[i];
38.1569 + if (text.regionMatches(true, start,
38.1570 + zoneName, 0, zoneName.length())) {
38.1571 + return i;
38.1572 + }
38.1573 + }
38.1574 + return -1;
38.1575 + }
38.1576 +
38.1577 + private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
38.1578 + String[][] zoneStrings) {
38.1579 + int index = standardIndex + 2;
38.1580 + String zoneName = zoneStrings[zoneIndex][index];
38.1581 + if (text.regionMatches(true, start,
38.1582 + zoneName, 0, zoneName.length())) {
38.1583 + return true;
38.1584 + }
38.1585 + return false;
38.1586 + }
38.1587 +
38.1588 + /**
38.1589 + * find time zone 'text' matched zoneStrings and set to internal
38.1590 + * calendar.
38.1591 + */
38.1592 + private int subParseZoneString(String text, int start, CalendarBuilder calb) {
38.1593 + boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
38.1594 + TimeZone currentTimeZone = getTimeZone();
38.1595 +
38.1596 + // At this point, check for named time zones by looking through
38.1597 + // the locale data from the TimeZoneNames strings.
38.1598 + // Want to be able to parse both short and long forms.
38.1599 + int zoneIndex = formatData.getZoneIndex(currentTimeZone.getID());
38.1600 + TimeZone tz = null;
38.1601 + String[][] zoneStrings = formatData.getZoneStringsWrapper();
38.1602 + String[] zoneNames = null;
38.1603 + int nameIndex = 0;
38.1604 + if (zoneIndex != -1) {
38.1605 + zoneNames = zoneStrings[zoneIndex];
38.1606 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
38.1607 + if (nameIndex <= 2) {
38.1608 + // Check if the standard name (abbr) and the daylight name are the same.
38.1609 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
38.1610 + }
38.1611 + tz = TimeZone.getTimeZone(zoneNames[0]);
38.1612 + }
38.1613 + }
38.1614 + if (tz == null) {
38.1615 + zoneIndex = formatData.getZoneIndex(TimeZone.getDefault().getID());
38.1616 + if (zoneIndex != -1) {
38.1617 + zoneNames = zoneStrings[zoneIndex];
38.1618 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
38.1619 + if (nameIndex <= 2) {
38.1620 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
38.1621 + }
38.1622 + tz = TimeZone.getTimeZone(zoneNames[0]);
38.1623 + }
38.1624 + }
38.1625 + }
38.1626 +
38.1627 + if (tz == null) {
38.1628 + int len = zoneStrings.length;
38.1629 + for (int i = 0; i < len; i++) {
38.1630 + zoneNames = zoneStrings[i];
38.1631 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
38.1632 + if (nameIndex <= 2) {
38.1633 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
38.1634 + }
38.1635 + tz = TimeZone.getTimeZone(zoneNames[0]);
38.1636 + break;
38.1637 + }
38.1638 + }
38.1639 + }
38.1640 + if (tz != null) { // Matched any ?
38.1641 + if (!tz.equals(currentTimeZone)) {
38.1642 + setTimeZone(tz);
38.1643 + }
38.1644 + // If the time zone matched uses the same name
38.1645 + // (abbreviation) for both standard and daylight time,
38.1646 + // let the time zone in the Calendar decide which one.
38.1647 + //
38.1648 + // Also if tz.getDSTSaving() returns 0 for DST, use tz to
38.1649 + // determine the local time. (6645292)
38.1650 + int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
38.1651 + if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
38.1652 + calb.set(Calendar.ZONE_OFFSET, tz.getRawOffset())
38.1653 + .set(Calendar.DST_OFFSET, dstAmount);
38.1654 + }
38.1655 + return (start + zoneNames[nameIndex].length());
38.1656 + }
38.1657 + return 0;
38.1658 + }
38.1659 +
38.1660 + /**
38.1661 + * Parses numeric forms of time zone offset, such as "hh:mm", and
38.1662 + * sets calb to the parsed value.
38.1663 + *
38.1664 + * @param text the text to be parsed
38.1665 + * @param start the character position to start parsing
38.1666 + * @param sign 1: positive; -1: negative
38.1667 + * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
38.1668 + * @param colon true - colon required between hh and mm; false - no colon required
38.1669 + * @param calb a CalendarBuilder in which the parsed value is stored
38.1670 + * @return updated parsed position, or its negative value to indicate a parsing error
38.1671 + */
38.1672 + private int subParseNumericZone(String text, int start, int sign, int count,
38.1673 + boolean colon, CalendarBuilder calb) {
38.1674 + int index = start;
38.1675 +
38.1676 + parse:
38.1677 + try {
38.1678 + char c = text.charAt(index++);
38.1679 + // Parse hh
38.1680 + int hours;
38.1681 + if (!isDigit(c)) {
38.1682 + break parse;
38.1683 + }
38.1684 + hours = c - '0';
38.1685 + c = text.charAt(index++);
38.1686 + if (isDigit(c)) {
38.1687 + hours = hours * 10 + (c - '0');
38.1688 + } else {
38.1689 + // If no colon in RFC 822 or 'X' (ISO), two digits are
38.1690 + // required.
38.1691 + if (count > 0 || !colon) {
38.1692 + break parse;
38.1693 + }
38.1694 + --index;
38.1695 + }
38.1696 + if (hours > 23) {
38.1697 + break parse;
38.1698 + }
38.1699 + int minutes = 0;
38.1700 + if (count != 1) {
38.1701 + // Proceed with parsing mm
38.1702 + c = text.charAt(index++);
38.1703 + if (colon) {
38.1704 + if (c != ':') {
38.1705 + break parse;
38.1706 + }
38.1707 + c = text.charAt(index++);
38.1708 + }
38.1709 + if (!isDigit(c)) {
38.1710 + break parse;
38.1711 + }
38.1712 + minutes = c - '0';
38.1713 + c = text.charAt(index++);
38.1714 + if (!isDigit(c)) {
38.1715 + break parse;
38.1716 + }
38.1717 + minutes = minutes * 10 + (c - '0');
38.1718 + if (minutes > 59) {
38.1719 + break parse;
38.1720 + }
38.1721 + }
38.1722 + minutes += hours * 60;
38.1723 + calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
38.1724 + .set(Calendar.DST_OFFSET, 0);
38.1725 + return index;
38.1726 + } catch (IndexOutOfBoundsException e) {
38.1727 + }
38.1728 + return 1 - index; // -(index - 1)
38.1729 + }
38.1730 +
38.1731 + private boolean isDigit(char c) {
38.1732 + return c >= '0' && c <= '9';
38.1733 + }
38.1734 +
38.1735 + /**
38.1736 + * Private member function that converts the parsed date strings into
38.1737 + * timeFields. Returns -start (for ParsePosition) if failed.
38.1738 + * @param text the time text to be parsed.
38.1739 + * @param start where to start parsing.
38.1740 + * @param ch the pattern character for the date field text to be parsed.
38.1741 + * @param count the count of a pattern character.
38.1742 + * @param obeyCount if true, then the next field directly abuts this one,
38.1743 + * and we should use the count to know when to stop parsing.
38.1744 + * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
38.1745 + * is true, then a two-digit year was parsed and may need to be readjusted.
38.1746 + * @param origPos origPos.errorIndex is used to return an error index
38.1747 + * at which a parse error occurred, if matching failure occurs.
38.1748 + * @return the new start position if matching succeeded; -1 indicating
38.1749 + * matching failure, otherwise. In case matching failure occurred,
38.1750 + * an error index is set to origPos.errorIndex.
38.1751 + */
38.1752 + private int subParse(String text, int start, int patternCharIndex, int count,
38.1753 + boolean obeyCount, boolean[] ambiguousYear,
38.1754 + ParsePosition origPos,
38.1755 + boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
38.1756 + Number number = null;
38.1757 + int value = 0;
38.1758 + ParsePosition pos = new ParsePosition(0);
38.1759 + pos.index = start;
38.1760 + if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
38.1761 + // use calendar year 'y' instead
38.1762 + patternCharIndex = PATTERN_YEAR;
38.1763 + }
38.1764 + int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
38.1765 +
38.1766 + // If there are any spaces here, skip over them. If we hit the end
38.1767 + // of the string, then fail.
38.1768 + for (;;) {
38.1769 + if (pos.index >= text.length()) {
38.1770 + origPos.errorIndex = start;
38.1771 + return -1;
38.1772 + }
38.1773 + char c = text.charAt(pos.index);
38.1774 + if (c != ' ' && c != '\t') break;
38.1775 + ++pos.index;
38.1776 + }
38.1777 +
38.1778 + parsing:
38.1779 + {
38.1780 + // We handle a few special cases here where we need to parse
38.1781 + // a number value. We handle further, more generic cases below. We need
38.1782 + // to handle some of them here because some fields require extra processing on
38.1783 + // the parsed value.
38.1784 + if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
38.1785 + patternCharIndex == PATTERN_HOUR1 ||
38.1786 + (patternCharIndex == PATTERN_MONTH && count <= 2) ||
38.1787 + patternCharIndex == PATTERN_YEAR ||
38.1788 + patternCharIndex == PATTERN_WEEK_YEAR) {
38.1789 + // It would be good to unify this with the obeyCount logic below,
38.1790 + // but that's going to be difficult.
38.1791 + if (obeyCount) {
38.1792 + if ((start+count) > text.length()) {
38.1793 + break parsing;
38.1794 + }
38.1795 + number = numberFormat.parse(text.substring(0, start+count), pos);
38.1796 + } else {
38.1797 + number = numberFormat.parse(text, pos);
38.1798 + }
38.1799 + if (number == null) {
38.1800 + if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
38.1801 + break parsing;
38.1802 + }
38.1803 + } else {
38.1804 + value = number.intValue();
38.1805 +
38.1806 + if (useFollowingMinusSignAsDelimiter && (value < 0) &&
38.1807 + (((pos.index < text.length()) &&
38.1808 + (text.charAt(pos.index) != minusSign)) ||
38.1809 + ((pos.index == text.length()) &&
38.1810 + (text.charAt(pos.index-1) == minusSign)))) {
38.1811 + value = -value;
38.1812 + pos.index--;
38.1813 + }
38.1814 + }
38.1815 + }
38.1816 +
38.1817 + boolean useDateFormatSymbols = useDateFormatSymbols();
38.1818 +
38.1819 + int index;
38.1820 + switch (patternCharIndex) {
38.1821 + case PATTERN_ERA: // 'G'
38.1822 + if (useDateFormatSymbols) {
38.1823 + if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
38.1824 + return index;
38.1825 + }
38.1826 + } else {
38.1827 + Map<String, Integer> map = calendar.getDisplayNames(field,
38.1828 + Calendar.ALL_STYLES,
38.1829 + locale);
38.1830 + if ((index = matchString(text, start, field, map, calb)) > 0) {
38.1831 + return index;
38.1832 + }
38.1833 + }
38.1834 + break parsing;
38.1835 +
38.1836 + case PATTERN_WEEK_YEAR: // 'Y'
38.1837 + case PATTERN_YEAR: // 'y'
38.1838 + if (!(calendar instanceof GregorianCalendar)) {
38.1839 + // calendar might have text representations for year values,
38.1840 + // such as "\u5143" in JapaneseImperialCalendar.
38.1841 + int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
38.1842 + Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
38.1843 + if (map != null) {
38.1844 + if ((index = matchString(text, start, field, map, calb)) > 0) {
38.1845 + return index;
38.1846 + }
38.1847 + }
38.1848 + calb.set(field, value);
38.1849 + return pos.index;
38.1850 + }
38.1851 +
38.1852 + // If there are 3 or more YEAR pattern characters, this indicates
38.1853 + // that the year value is to be treated literally, without any
38.1854 + // two-digit year adjustments (e.g., from "01" to 2001). Otherwise
38.1855 + // we made adjustments to place the 2-digit year in the proper
38.1856 + // century, for parsed strings from "00" to "99". Any other string
38.1857 + // is treated literally: "2250", "-1", "1", "002".
38.1858 + if (count <= 2 && (pos.index - start) == 2
38.1859 + && Character.isDigit(text.charAt(start))
38.1860 + && Character.isDigit(text.charAt(start+1))) {
38.1861 + // Assume for example that the defaultCenturyStart is 6/18/1903.
38.1862 + // This means that two-digit years will be forced into the range
38.1863 + // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02
38.1864 + // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond
38.1865 + // to 1904, 1905, etc. If the year is 03, then it is 2003 if the
38.1866 + // other fields specify a date before 6/18, or 1903 if they specify a
38.1867 + // date afterwards. As a result, 03 is an ambiguous year. All other
38.1868 + // two-digit years are unambiguous.
38.1869 + int ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
38.1870 + ambiguousYear[0] = value == ambiguousTwoDigitYear;
38.1871 + value += (defaultCenturyStartYear/100)*100 +
38.1872 + (value < ambiguousTwoDigitYear ? 100 : 0);
38.1873 + }
38.1874 + calb.set(field, value);
38.1875 + return pos.index;
38.1876 +
38.1877 + case PATTERN_MONTH: // 'M'
38.1878 + if (count <= 2) // i.e., M or MM.
38.1879 + {
38.1880 + // Don't want to parse the month if it is a string
38.1881 + // while pattern uses numeric style: M or MM.
38.1882 + // [We computed 'value' above.]
38.1883 + calb.set(Calendar.MONTH, value - 1);
38.1884 + return pos.index;
38.1885 + }
38.1886 +
38.1887 + if (useDateFormatSymbols) {
38.1888 + // count >= 3 // i.e., MMM or MMMM
38.1889 + // Want to be able to parse both short and long forms.
38.1890 + // Try count == 4 first:
38.1891 + int newStart = 0;
38.1892 + if ((newStart = matchString(text, start, Calendar.MONTH,
38.1893 + formatData.getMonths(), calb)) > 0) {
38.1894 + return newStart;
38.1895 + }
38.1896 + // count == 4 failed, now try count == 3
38.1897 + if ((index = matchString(text, start, Calendar.MONTH,
38.1898 + formatData.getShortMonths(), calb)) > 0) {
38.1899 + return index;
38.1900 + }
38.1901 + } else {
38.1902 + Map<String, Integer> map = calendar.getDisplayNames(field,
38.1903 + Calendar.ALL_STYLES,
38.1904 + locale);
38.1905 + if ((index = matchString(text, start, field, map, calb)) > 0) {
38.1906 + return index;
38.1907 + }
38.1908 + }
38.1909 + break parsing;
38.1910 +
38.1911 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
38.1912 + if (!isLenient()) {
38.1913 + // Validate the hour value in non-lenient
38.1914 + if (value < 1 || value > 24) {
38.1915 + break parsing;
38.1916 + }
38.1917 + }
38.1918 + // [We computed 'value' above.]
38.1919 + if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1)
38.1920 + value = 0;
38.1921 + calb.set(Calendar.HOUR_OF_DAY, value);
38.1922 + return pos.index;
38.1923 +
38.1924 + case PATTERN_DAY_OF_WEEK: // 'E'
38.1925 + {
38.1926 + if (useDateFormatSymbols) {
38.1927 + // Want to be able to parse both short and long forms.
38.1928 + // Try count == 4 (DDDD) first:
38.1929 + int newStart = 0;
38.1930 + if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
38.1931 + formatData.getWeekdays(), calb)) > 0) {
38.1932 + return newStart;
38.1933 + }
38.1934 + // DDDD failed, now try DDD
38.1935 + if ((index = matchString(text, start, Calendar.DAY_OF_WEEK,
38.1936 + formatData.getShortWeekdays(), calb)) > 0) {
38.1937 + return index;
38.1938 + }
38.1939 + } else {
38.1940 + int[] styles = { Calendar.LONG, Calendar.SHORT };
38.1941 + for (int style : styles) {
38.1942 + Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
38.1943 + if ((index = matchString(text, start, field, map, calb)) > 0) {
38.1944 + return index;
38.1945 + }
38.1946 + }
38.1947 + }
38.1948 + }
38.1949 + break parsing;
38.1950 +
38.1951 + case PATTERN_AM_PM: // 'a'
38.1952 + if (useDateFormatSymbols) {
38.1953 + if ((index = matchString(text, start, Calendar.AM_PM,
38.1954 + formatData.getAmPmStrings(), calb)) > 0) {
38.1955 + return index;
38.1956 + }
38.1957 + } else {
38.1958 + Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
38.1959 + if ((index = matchString(text, start, field, map, calb)) > 0) {
38.1960 + return index;
38.1961 + }
38.1962 + }
38.1963 + break parsing;
38.1964 +
38.1965 + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
38.1966 + if (!isLenient()) {
38.1967 + // Validate the hour value in non-lenient
38.1968 + if (value < 1 || value > 12) {
38.1969 + break parsing;
38.1970 + }
38.1971 + }
38.1972 + // [We computed 'value' above.]
38.1973 + if (value == calendar.getLeastMaximum(Calendar.HOUR)+1)
38.1974 + value = 0;
38.1975 + calb.set(Calendar.HOUR, value);
38.1976 + return pos.index;
38.1977 +
38.1978 + case PATTERN_ZONE_NAME: // 'z'
38.1979 + case PATTERN_ZONE_VALUE: // 'Z'
38.1980 + {
38.1981 + int sign = 0;
38.1982 + try {
38.1983 + char c = text.charAt(pos.index);
38.1984 + if (c == '+') {
38.1985 + sign = 1;
38.1986 + } else if (c == '-') {
38.1987 + sign = -1;
38.1988 + }
38.1989 + if (sign == 0) {
38.1990 + // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
38.1991 + if ((c == 'G' || c == 'g')
38.1992 + && (text.length() - start) >= GMT.length()
38.1993 + && text.regionMatches(true, start, GMT, 0, GMT.length())) {
38.1994 + pos.index = start + GMT.length();
38.1995 +
38.1996 + if ((text.length() - pos.index) > 0) {
38.1997 + c = text.charAt(pos.index);
38.1998 + if (c == '+') {
38.1999 + sign = 1;
38.2000 + } else if (c == '-') {
38.2001 + sign = -1;
38.2002 + }
38.2003 + }
38.2004 +
38.2005 + if (sign == 0) { /* "GMT" without offset */
38.2006 + calb.set(Calendar.ZONE_OFFSET, 0)
38.2007 + .set(Calendar.DST_OFFSET, 0);
38.2008 + return pos.index;
38.2009 + }
38.2010 +
38.2011 + // Parse the rest as "hh:mm"
38.2012 + int i = subParseNumericZone(text, ++pos.index,
38.2013 + sign, 0, true, calb);
38.2014 + if (i > 0) {
38.2015 + return i;
38.2016 + }
38.2017 + pos.index = -i;
38.2018 + } else {
38.2019 + // Try parsing the text as a time zone
38.2020 + // name or abbreviation.
38.2021 + int i = subParseZoneString(text, pos.index, calb);
38.2022 + if (i > 0) {
38.2023 + return i;
38.2024 + }
38.2025 + pos.index = -i;
38.2026 + }
38.2027 + } else {
38.2028 + // Parse the rest as "hhmm" (RFC 822)
38.2029 + int i = subParseNumericZone(text, ++pos.index,
38.2030 + sign, 0, false, calb);
38.2031 + if (i > 0) {
38.2032 + return i;
38.2033 + }
38.2034 + pos.index = -i;
38.2035 + }
38.2036 + } catch (IndexOutOfBoundsException e) {
38.2037 + }
38.2038 + }
38.2039 + break parsing;
38.2040 +
38.2041 + case PATTERN_ISO_ZONE: // 'X'
38.2042 + {
38.2043 + if ((text.length() - pos.index) <= 0) {
38.2044 + break parsing;
38.2045 + }
38.2046 +
38.2047 + int sign = 0;
38.2048 + char c = text.charAt(pos.index);
38.2049 + if (c == 'Z') {
38.2050 + calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
38.2051 + return ++pos.index;
38.2052 + }
38.2053 +
38.2054 + // parse text as "+/-hh[[:]mm]" based on count
38.2055 + if (c == '+') {
38.2056 + sign = 1;
38.2057 + } else if (c == '-') {
38.2058 + sign = -1;
38.2059 + } else {
38.2060 + ++pos.index;
38.2061 + break parsing;
38.2062 + }
38.2063 + int i = subParseNumericZone(text, ++pos.index, sign, count,
38.2064 + count == 3, calb);
38.2065 + if (i > 0) {
38.2066 + return i;
38.2067 + }
38.2068 + pos.index = -i;
38.2069 + }
38.2070 + break parsing;
38.2071 +
38.2072 + default:
38.2073 + // case PATTERN_DAY_OF_MONTH: // 'd'
38.2074 + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
38.2075 + // case PATTERN_MINUTE: // 'm'
38.2076 + // case PATTERN_SECOND: // 's'
38.2077 + // case PATTERN_MILLISECOND: // 'S'
38.2078 + // case PATTERN_DAY_OF_YEAR: // 'D'
38.2079 + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
38.2080 + // case PATTERN_WEEK_OF_YEAR: // 'w'
38.2081 + // case PATTERN_WEEK_OF_MONTH: // 'W'
38.2082 + // case PATTERN_HOUR0: // 'K' 0-based. eg, 11PM + 1 hour =>> 0 AM
38.2083 + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' (pseudo field);
38.2084 +
38.2085 + // Handle "generic" fields
38.2086 + if (obeyCount) {
38.2087 + if ((start+count) > text.length()) {
38.2088 + break parsing;
38.2089 + }
38.2090 + number = numberFormat.parse(text.substring(0, start+count), pos);
38.2091 + } else {
38.2092 + number = numberFormat.parse(text, pos);
38.2093 + }
38.2094 + if (number != null) {
38.2095 + value = number.intValue();
38.2096 +
38.2097 + if (useFollowingMinusSignAsDelimiter && (value < 0) &&
38.2098 + (((pos.index < text.length()) &&
38.2099 + (text.charAt(pos.index) != minusSign)) ||
38.2100 + ((pos.index == text.length()) &&
38.2101 + (text.charAt(pos.index-1) == minusSign)))) {
38.2102 + value = -value;
38.2103 + pos.index--;
38.2104 + }
38.2105 +
38.2106 + calb.set(field, value);
38.2107 + return pos.index;
38.2108 + }
38.2109 + break parsing;
38.2110 + }
38.2111 + }
38.2112 +
38.2113 + // Parsing failed.
38.2114 + origPos.errorIndex = pos.index;
38.2115 + return -1;
38.2116 + }
38.2117 +
38.2118 + private final String getCalendarName() {
38.2119 + return calendar.getClass().getName();
38.2120 + }
38.2121 +
38.2122 + private boolean useDateFormatSymbols() {
38.2123 + if (useDateFormatSymbols) {
38.2124 + return true;
38.2125 + }
38.2126 + return isGregorianCalendar() || locale == null;
38.2127 + }
38.2128 +
38.2129 + private boolean isGregorianCalendar() {
38.2130 + return "java.util.GregorianCalendar".equals(getCalendarName());
38.2131 + }
38.2132 +
38.2133 + /**
38.2134 + * Translates a pattern, mapping each character in the from string to the
38.2135 + * corresponding character in the to string.
38.2136 + *
38.2137 + * @exception IllegalArgumentException if the given pattern is invalid
38.2138 + */
38.2139 + private String translatePattern(String pattern, String from, String to) {
38.2140 + StringBuilder result = new StringBuilder();
38.2141 + boolean inQuote = false;
38.2142 + for (int i = 0; i < pattern.length(); ++i) {
38.2143 + char c = pattern.charAt(i);
38.2144 + if (inQuote) {
38.2145 + if (c == '\'')
38.2146 + inQuote = false;
38.2147 + }
38.2148 + else {
38.2149 + if (c == '\'')
38.2150 + inQuote = true;
38.2151 + else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
38.2152 + int ci = from.indexOf(c);
38.2153 + if (ci >= 0) {
38.2154 + // patternChars is longer than localPatternChars due
38.2155 + // to serialization compatibility. The pattern letters
38.2156 + // unsupported by localPatternChars pass through.
38.2157 + if (ci < to.length()) {
38.2158 + c = to.charAt(ci);
38.2159 + }
38.2160 + } else {
38.2161 + throw new IllegalArgumentException("Illegal pattern " +
38.2162 + " character '" +
38.2163 + c + "'");
38.2164 + }
38.2165 + }
38.2166 + }
38.2167 + result.append(c);
38.2168 + }
38.2169 + if (inQuote)
38.2170 + throw new IllegalArgumentException("Unfinished quote in pattern");
38.2171 + return result.toString();
38.2172 + }
38.2173 +
38.2174 + /**
38.2175 + * Returns a pattern string describing this date format.
38.2176 + *
38.2177 + * @return a pattern string describing this date format.
38.2178 + */
38.2179 + public String toPattern() {
38.2180 + return pattern;
38.2181 + }
38.2182 +
38.2183 + /**
38.2184 + * Returns a localized pattern string describing this date format.
38.2185 + *
38.2186 + * @return a localized pattern string describing this date format.
38.2187 + */
38.2188 + public String toLocalizedPattern() {
38.2189 + return translatePattern(pattern,
38.2190 + DateFormatSymbols.patternChars,
38.2191 + formatData.getLocalPatternChars());
38.2192 + }
38.2193 +
38.2194 + /**
38.2195 + * Applies the given pattern string to this date format.
38.2196 + *
38.2197 + * @param pattern the new date and time pattern for this date format
38.2198 + * @exception NullPointerException if the given pattern is null
38.2199 + * @exception IllegalArgumentException if the given pattern is invalid
38.2200 + */
38.2201 + public void applyPattern(String pattern)
38.2202 + {
38.2203 + compiledPattern = compile(pattern);
38.2204 + this.pattern = pattern;
38.2205 + }
38.2206 +
38.2207 + /**
38.2208 + * Applies the given localized pattern string to this date format.
38.2209 + *
38.2210 + * @param pattern a String to be mapped to the new date and time format
38.2211 + * pattern for this format
38.2212 + * @exception NullPointerException if the given pattern is null
38.2213 + * @exception IllegalArgumentException if the given pattern is invalid
38.2214 + */
38.2215 + public void applyLocalizedPattern(String pattern) {
38.2216 + String p = translatePattern(pattern,
38.2217 + formatData.getLocalPatternChars(),
38.2218 + DateFormatSymbols.patternChars);
38.2219 + compiledPattern = compile(p);
38.2220 + this.pattern = p;
38.2221 + }
38.2222 +
38.2223 + /**
38.2224 + * Gets a copy of the date and time format symbols of this date format.
38.2225 + *
38.2226 + * @return the date and time format symbols of this date format
38.2227 + * @see #setDateFormatSymbols
38.2228 + */
38.2229 + public DateFormatSymbols getDateFormatSymbols()
38.2230 + {
38.2231 + return (DateFormatSymbols)formatData.clone();
38.2232 + }
38.2233 +
38.2234 + /**
38.2235 + * Sets the date and time format symbols of this date format.
38.2236 + *
38.2237 + * @param newFormatSymbols the new date and time format symbols
38.2238 + * @exception NullPointerException if the given newFormatSymbols is null
38.2239 + * @see #getDateFormatSymbols
38.2240 + */
38.2241 + public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
38.2242 + {
38.2243 + this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
38.2244 + useDateFormatSymbols = true;
38.2245 + }
38.2246 +
38.2247 + /**
38.2248 + * Creates a copy of this <code>SimpleDateFormat</code>. This also
38.2249 + * clones the format's date format symbols.
38.2250 + *
38.2251 + * @return a clone of this <code>SimpleDateFormat</code>
38.2252 + */
38.2253 + public Object clone() {
38.2254 + SimpleDateFormat other = (SimpleDateFormat) super.clone();
38.2255 + other.formatData = (DateFormatSymbols) formatData.clone();
38.2256 + return other;
38.2257 + }
38.2258 +
38.2259 + /**
38.2260 + * Returns the hash code value for this <code>SimpleDateFormat</code> object.
38.2261 + *
38.2262 + * @return the hash code value for this <code>SimpleDateFormat</code> object.
38.2263 + */
38.2264 + public int hashCode()
38.2265 + {
38.2266 + return pattern.hashCode();
38.2267 + // just enough fields for a reasonable distribution
38.2268 + }
38.2269 +
38.2270 + /**
38.2271 + * Compares the given object with this <code>SimpleDateFormat</code> for
38.2272 + * equality.
38.2273 + *
38.2274 + * @return true if the given object is equal to this
38.2275 + * <code>SimpleDateFormat</code>
38.2276 + */
38.2277 + public boolean equals(Object obj)
38.2278 + {
38.2279 + if (!super.equals(obj)) return false; // super does class check
38.2280 + SimpleDateFormat that = (SimpleDateFormat) obj;
38.2281 + return (pattern.equals(that.pattern)
38.2282 + && formatData.equals(that.formatData));
38.2283 + }
38.2284 +
38.2285 + /**
38.2286 + * After reading an object from the input stream, the format
38.2287 + * pattern in the object is verified.
38.2288 + * <p>
38.2289 + * @exception InvalidObjectException if the pattern is invalid
38.2290 + */
38.2291 + private void readObject(ObjectInputStream stream)
38.2292 + throws IOException, ClassNotFoundException {
38.2293 + stream.defaultReadObject();
38.2294 +
38.2295 + try {
38.2296 + compiledPattern = compile(pattern);
38.2297 + } catch (Exception e) {
38.2298 + throw new InvalidObjectException("invalid pattern");
38.2299 + }
38.2300 +
38.2301 + if (serialVersionOnStream < 1) {
38.2302 + // didn't have defaultCenturyStart field
38.2303 + initializeDefaultCentury();
38.2304 + }
38.2305 + else {
38.2306 + // fill in dependent transient field
38.2307 + parseAmbiguousDatesAsAfter(defaultCenturyStart);
38.2308 + }
38.2309 + serialVersionOnStream = currentSerialVersion;
38.2310 +
38.2311 + // If the deserialized object has a SimpleTimeZone, try
38.2312 + // to replace it with a ZoneInfo equivalent in order to
38.2313 + // be compatible with the SimpleTimeZone-based
38.2314 + // implementation as much as possible.
38.2315 + TimeZone tz = getTimeZone();
38.2316 + if (tz instanceof SimpleTimeZone) {
38.2317 + String id = tz.getID();
38.2318 + TimeZone zi = TimeZone.getTimeZone(id);
38.2319 + if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) {
38.2320 + setTimeZone(zi);
38.2321 + }
38.2322 + }
38.2323 + }
38.2324 +
38.2325 + /**
38.2326 + * Analyze the negative subpattern of DecimalFormat and set/update values
38.2327 + * as necessary.
38.2328 + */
38.2329 + private void checkNegativeNumberExpression() {
38.2330 + if ((numberFormat instanceof DecimalFormat) &&
38.2331 + !numberFormat.equals(originalNumberFormat)) {
38.2332 + String numberPattern = ((DecimalFormat)numberFormat).toPattern();
38.2333 + if (!numberPattern.equals(originalNumberPattern)) {
38.2334 + hasFollowingMinusSign = false;
38.2335 +
38.2336 + int separatorIndex = numberPattern.indexOf(';');
38.2337 + // If the negative subpattern is not absent, we have to analayze
38.2338 + // it in order to check if it has a following minus sign.
38.2339 + if (separatorIndex > -1) {
38.2340 + int minusIndex = numberPattern.indexOf('-', separatorIndex);
38.2341 + if ((minusIndex > numberPattern.lastIndexOf('0')) &&
38.2342 + (minusIndex > numberPattern.lastIndexOf('#'))) {
38.2343 + hasFollowingMinusSign = true;
38.2344 + minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign();
38.2345 + }
38.2346 + }
38.2347 + originalNumberPattern = numberPattern;
38.2348 + }
38.2349 + originalNumberFormat = numberFormat;
38.2350 + }
38.2351 + }
38.2352 +
38.2353 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/rt/emul/compact/src/main/java/java/util/Calendar.java Thu Oct 03 15:40:35 2013 +0200
39.3 @@ -0,0 +1,2824 @@
39.4 +/*
39.5 + * Copyright (c) 1996, 2011, 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-1998 - 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.util;
39.43 +
39.44 +import java.io.IOException;
39.45 +import java.io.ObjectInputStream;
39.46 +import java.io.ObjectOutputStream;
39.47 +import java.io.OptionalDataException;
39.48 +import java.io.Serializable;
39.49 +import java.security.AccessControlContext;
39.50 +import java.security.AccessController;
39.51 +import java.security.PermissionCollection;
39.52 +import java.security.PrivilegedActionException;
39.53 +import java.security.PrivilegedExceptionAction;
39.54 +import java.security.ProtectionDomain;
39.55 +import java.text.DateFormat;
39.56 +import java.text.DateFormatSymbols;
39.57 +import java.util.concurrent.ConcurrentHashMap;
39.58 +import java.util.concurrent.ConcurrentMap;
39.59 +import sun.util.BuddhistCalendar;
39.60 +import sun.util.calendar.ZoneInfo;
39.61 +import sun.util.resources.LocaleData;
39.62 +
39.63 +/**
39.64 + * The <code>Calendar</code> class is an abstract class that provides methods
39.65 + * for converting between a specific instant in time and a set of {@link
39.66 + * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
39.67 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
39.68 + * manipulating the calendar fields, such as getting the date of the next
39.69 + * week. An instant in time can be represented by a millisecond value that is
39.70 + * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
39.71 + * 00:00:00.000 GMT (Gregorian).
39.72 + *
39.73 + * <p>The class also provides additional fields and methods for
39.74 + * implementing a concrete calendar system outside the package. Those
39.75 + * fields and methods are defined as <code>protected</code>.
39.76 + *
39.77 + * <p>
39.78 + * Like other locale-sensitive classes, <code>Calendar</code> provides a
39.79 + * class method, <code>getInstance</code>, for getting a generally useful
39.80 + * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
39.81 + * returns a <code>Calendar</code> object whose
39.82 + * calendar fields have been initialized with the current date and time:
39.83 + * <blockquote>
39.84 + * <pre>
39.85 + * Calendar rightNow = Calendar.getInstance();
39.86 + * </pre>
39.87 + * </blockquote>
39.88 + *
39.89 + * <p>A <code>Calendar</code> object can produce all the calendar field values
39.90 + * needed to implement the date-time formatting for a particular language and
39.91 + * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
39.92 + * <code>Calendar</code> defines the range of values returned by
39.93 + * certain calendar fields, as well as their meaning. For example,
39.94 + * the first month of the calendar system has value <code>MONTH ==
39.95 + * JANUARY</code> for all calendars. Other values are defined by the
39.96 + * concrete subclass, such as <code>ERA</code>. See individual field
39.97 + * documentation and subclass documentation for details.
39.98 + *
39.99 + * <h4>Getting and Setting Calendar Field Values</h4>
39.100 + *
39.101 + * <p>The calendar field values can be set by calling the <code>set</code>
39.102 + * methods. Any field values set in a <code>Calendar</code> will not be
39.103 + * interpreted until it needs to calculate its time value (milliseconds from
39.104 + * the Epoch) or values of the calendar fields. Calling the
39.105 + * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
39.106 + * <code>add</code> and <code>roll</code> involves such calculation.
39.107 + *
39.108 + * <h4>Leniency</h4>
39.109 + *
39.110 + * <p><code>Calendar</code> has two modes for interpreting the calendar
39.111 + * fields, <em>lenient</em> and <em>non-lenient</em>. When a
39.112 + * <code>Calendar</code> is in lenient mode, it accepts a wider range of
39.113 + * calendar field values than it produces. When a <code>Calendar</code>
39.114 + * recomputes calendar field values for return by <code>get()</code>, all of
39.115 + * the calendar fields are normalized. For example, a lenient
39.116 + * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
39.117 + * <code>DAY_OF_MONTH == 32</code> as February 1.
39.118 +
39.119 + * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
39.120 + * exception if there is any inconsistency in its calendar fields. For
39.121 + * example, a <code>GregorianCalendar</code> always produces
39.122 + * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
39.123 + * non-lenient <code>GregorianCalendar</code> throws an exception upon
39.124 + * calculating its time or calendar field values if any out-of-range field
39.125 + * value has been set.
39.126 + *
39.127 + * <h4><a name="first_week">First Week</a></h4>
39.128 + *
39.129 + * <code>Calendar</code> defines a locale-specific seven day week using two
39.130 + * parameters: the first day of the week and the minimal days in first week
39.131 + * (from 1 to 7). These numbers are taken from the locale resource data when a
39.132 + * <code>Calendar</code> is constructed. They may also be specified explicitly
39.133 + * through the methods for setting their values.
39.134 + *
39.135 + * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
39.136 + * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
39.137 + * first week of the month or year as a reference point. The first week of a
39.138 + * month or year is defined as the earliest seven day period beginning on
39.139 + * <code>getFirstDayOfWeek()</code> and containing at least
39.140 + * <code>getMinimalDaysInFirstWeek()</code> days of that month or year. Weeks
39.141 + * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
39.142 + * it. Note that the normalized numbering returned by <code>get()</code> may be
39.143 + * different. For example, a specific <code>Calendar</code> subclass may
39.144 + * designate the week before week 1 of a year as week <code><i>n</i></code> of
39.145 + * the previous year.
39.146 + *
39.147 + * <h4>Calendar Fields Resolution</h4>
39.148 + *
39.149 + * When computing a date and time from the calendar fields, there
39.150 + * may be insufficient information for the computation (such as only
39.151 + * year and month with no day of month), or there may be inconsistent
39.152 + * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
39.153 + * 1996 is actually a Monday). <code>Calendar</code> will resolve
39.154 + * calendar field values to determine the date and time in the
39.155 + * following way.
39.156 + *
39.157 + * <p>If there is any conflict in calendar field values,
39.158 + * <code>Calendar</code> gives priorities to calendar fields that have been set
39.159 + * more recently. The following are the default combinations of the
39.160 + * calendar fields. The most recent combination, as determined by the
39.161 + * most recently set single field, will be used.
39.162 + *
39.163 + * <p><a name="date_resolution">For the date fields</a>:
39.164 + * <blockquote>
39.165 + * <pre>
39.166 + * YEAR + MONTH + DAY_OF_MONTH
39.167 + * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
39.168 + * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
39.169 + * YEAR + DAY_OF_YEAR
39.170 + * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
39.171 + * </pre></blockquote>
39.172 + *
39.173 + * <a name="time_resolution">For the time of day fields</a>:
39.174 + * <blockquote>
39.175 + * <pre>
39.176 + * HOUR_OF_DAY
39.177 + * AM_PM + HOUR
39.178 + * </pre></blockquote>
39.179 + *
39.180 + * <p>If there are any calendar fields whose values haven't been set in the selected
39.181 + * field combination, <code>Calendar</code> uses their default values. The default
39.182 + * value of each field may vary by concrete calendar systems. For example, in
39.183 + * <code>GregorianCalendar</code>, the default of a field is the same as that
39.184 + * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
39.185 + * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
39.186 + *
39.187 + * <p>
39.188 + * <strong>Note:</strong> There are certain possible ambiguities in
39.189 + * interpretation of certain singular times, which are resolved in the
39.190 + * following ways:
39.191 + * <ol>
39.192 + * <li> 23:59 is the last minute of the day and 00:00 is the first
39.193 + * minute of the next day. Thus, 23:59 on Dec 31, 1999 < 00:00 on
39.194 + * Jan 1, 2000 < 00:01 on Jan 1, 2000.
39.195 + *
39.196 + * <li> Although historically not precise, midnight also belongs to "am",
39.197 + * and noon belongs to "pm", so on the same day,
39.198 + * 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm
39.199 + * </ol>
39.200 + *
39.201 + * <p>
39.202 + * The date or time format strings are not part of the definition of a
39.203 + * calendar, as those must be modifiable or overridable by the user at
39.204 + * runtime. Use {@link DateFormat}
39.205 + * to format dates.
39.206 + *
39.207 + * <h4>Field Manipulation</h4>
39.208 + *
39.209 + * The calendar fields can be changed using three methods:
39.210 + * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.</p>
39.211 + *
39.212 + * <p><strong><code>set(f, value)</code></strong> changes calendar field
39.213 + * <code>f</code> to <code>value</code>. In addition, it sets an
39.214 + * internal member variable to indicate that calendar field <code>f</code> has
39.215 + * been changed. Although calendar field <code>f</code> is changed immediately,
39.216 + * the calendar's time value in milliseconds is not recomputed until the next call to
39.217 + * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
39.218 + * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
39.219 + * <code>set()</code> do not trigger multiple, unnecessary
39.220 + * computations. As a result of changing a calendar field using
39.221 + * <code>set()</code>, other calendar fields may also change, depending on the
39.222 + * calendar field, the calendar field value, and the calendar system. In addition,
39.223 + * <code>get(f)</code> will not necessarily return <code>value</code> set by
39.224 + * the call to the <code>set</code> method
39.225 + * after the calendar fields have been recomputed. The specifics are determined by
39.226 + * the concrete calendar class.</p>
39.227 + *
39.228 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
39.229 + * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
39.230 + * Calendar.SEPTEMBER)</code> sets the date to September 31,
39.231 + * 1999. This is a temporary internal representation that resolves to
39.232 + * October 1, 1999 if <code>getTime()</code>is then called. However, a
39.233 + * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
39.234 + * <code>getTime()</code> sets the date to September 30, 1999, since
39.235 + * no recomputation occurs after <code>set()</code> itself.</p>
39.236 + *
39.237 + * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
39.238 + * to field <code>f</code>. This is equivalent to calling <code>set(f,
39.239 + * get(f) + delta)</code> with two adjustments:</p>
39.240 + *
39.241 + * <blockquote>
39.242 + * <p><strong>Add rule 1</strong>. The value of field <code>f</code>
39.243 + * after the call minus the value of field <code>f</code> before the
39.244 + * call is <code>delta</code>, modulo any overflow that has occurred in
39.245 + * field <code>f</code>. Overflow occurs when a field value exceeds its
39.246 + * range and, as a result, the next larger field is incremented or
39.247 + * decremented and the field value is adjusted back into its range.</p>
39.248 + *
39.249 + * <p><strong>Add rule 2</strong>. If a smaller field is expected to be
39.250 + * invariant, but it is impossible for it to be equal to its
39.251 + * prior value because of changes in its minimum or maximum after field
39.252 + * <code>f</code> is changed or other constraints, such as time zone
39.253 + * offset changes, then its value is adjusted to be as close
39.254 + * as possible to its expected value. A smaller field represents a
39.255 + * smaller unit of time. <code>HOUR</code> is a smaller field than
39.256 + * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
39.257 + * that are not expected to be invariant. The calendar system
39.258 + * determines what fields are expected to be invariant.</p>
39.259 + * </blockquote>
39.260 + *
39.261 + * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
39.262 + * an immediate recomputation of the calendar's milliseconds and all
39.263 + * fields.</p>
39.264 + *
39.265 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
39.266 + * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
39.267 + * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
39.268 + * 1</strong> sets the <code>MONTH</code> field to September, since
39.269 + * adding 13 months to August gives September of the next year. Since
39.270 + * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
39.271 + * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
39.272 + * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
39.273 + * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
39.274 + * rule 2, since it is expected to change when the month changes in a
39.275 + * <code>GregorianCalendar</code>.</p>
39.276 + *
39.277 + * <p><strong><code>roll(f, delta)</code></strong> adds
39.278 + * <code>delta</code> to field <code>f</code> without changing larger
39.279 + * fields. This is equivalent to calling <code>add(f, delta)</code> with
39.280 + * the following adjustment:</p>
39.281 + *
39.282 + * <blockquote>
39.283 + * <p><strong>Roll rule</strong>. Larger fields are unchanged after the
39.284 + * call. A larger field represents a larger unit of
39.285 + * time. <code>DAY_OF_MONTH</code> is a larger field than
39.286 + * <code>HOUR</code>.</p>
39.287 + * </blockquote>
39.288 + *
39.289 + * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
39.290 + *
39.291 + * <p><strong>Usage model</strong>. To motivate the behavior of
39.292 + * <code>add()</code> and <code>roll()</code>, consider a user interface
39.293 + * component with increment and decrement buttons for the month, day, and
39.294 + * year, and an underlying <code>GregorianCalendar</code>. If the
39.295 + * interface reads January 31, 1999 and the user presses the month
39.296 + * increment button, what should it read? If the underlying
39.297 + * implementation uses <code>set()</code>, it might read March 3, 1999. A
39.298 + * better result would be February 28, 1999. Furthermore, if the user
39.299 + * presses the month increment button again, it should read March 31,
39.300 + * 1999, not March 28, 1999. By saving the original date and using either
39.301 + * <code>add()</code> or <code>roll()</code>, depending on whether larger
39.302 + * fields should be affected, the user interface can behave as most users
39.303 + * will intuitively expect.</p>
39.304 + *
39.305 + * @see java.lang.System#currentTimeMillis()
39.306 + * @see Date
39.307 + * @see GregorianCalendar
39.308 + * @see TimeZone
39.309 + * @see java.text.DateFormat
39.310 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
39.311 + * @since JDK1.1
39.312 + */
39.313 +public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
39.314 +
39.315 + // Data flow in Calendar
39.316 + // ---------------------
39.317 +
39.318 + // The current time is represented in two ways by Calendar: as UTC
39.319 + // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
39.320 + // fields such as MONTH, HOUR, AM_PM, etc. It is possible to compute the
39.321 + // millis from the fields, and vice versa. The data needed to do this
39.322 + // conversion is encapsulated by a TimeZone object owned by the Calendar.
39.323 + // The data provided by the TimeZone object may also be overridden if the
39.324 + // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
39.325 + // keeps track of what information was most recently set by the caller, and
39.326 + // uses that to compute any other information as needed.
39.327 +
39.328 + // If the user sets the fields using set(), the data flow is as follows.
39.329 + // This is implemented by the Calendar subclass's computeTime() method.
39.330 + // During this process, certain fields may be ignored. The disambiguation
39.331 + // algorithm for resolving which fields to pay attention to is described
39.332 + // in the class documentation.
39.333 +
39.334 + // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
39.335 + // |
39.336 + // | Using Calendar-specific algorithm
39.337 + // V
39.338 + // local standard millis
39.339 + // |
39.340 + // | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
39.341 + // V
39.342 + // UTC millis (in time data member)
39.343 +
39.344 + // If the user sets the UTC millis using setTime() or setTimeInMillis(),
39.345 + // the data flow is as follows. This is implemented by the Calendar
39.346 + // subclass's computeFields() method.
39.347 +
39.348 + // UTC millis (in time data member)
39.349 + // |
39.350 + // | Using TimeZone getOffset()
39.351 + // V
39.352 + // local standard millis
39.353 + // |
39.354 + // | Using Calendar-specific algorithm
39.355 + // V
39.356 + // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
39.357 +
39.358 + // In general, a round trip from fields, through local and UTC millis, and
39.359 + // back out to fields is made when necessary. This is implemented by the
39.360 + // complete() method. Resolving a partial set of fields into a UTC millis
39.361 + // value allows all remaining fields to be generated from that value. If
39.362 + // the Calendar is lenient, the fields are also renormalized to standard
39.363 + // ranges when they are regenerated.
39.364 +
39.365 + /**
39.366 + * Field number for <code>get</code> and <code>set</code> indicating the
39.367 + * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
39.368 + * value; see subclass documentation.
39.369 + *
39.370 + * @see GregorianCalendar#AD
39.371 + * @see GregorianCalendar#BC
39.372 + */
39.373 + public final static int ERA = 0;
39.374 +
39.375 + /**
39.376 + * Field number for <code>get</code> and <code>set</code> indicating the
39.377 + * year. This is a calendar-specific value; see subclass documentation.
39.378 + */
39.379 + public final static int YEAR = 1;
39.380 +
39.381 + /**
39.382 + * Field number for <code>get</code> and <code>set</code> indicating the
39.383 + * month. This is a calendar-specific value. The first month of
39.384 + * the year in the Gregorian and Julian calendars is
39.385 + * <code>JANUARY</code> which is 0; the last depends on the number
39.386 + * of months in a year.
39.387 + *
39.388 + * @see #JANUARY
39.389 + * @see #FEBRUARY
39.390 + * @see #MARCH
39.391 + * @see #APRIL
39.392 + * @see #MAY
39.393 + * @see #JUNE
39.394 + * @see #JULY
39.395 + * @see #AUGUST
39.396 + * @see #SEPTEMBER
39.397 + * @see #OCTOBER
39.398 + * @see #NOVEMBER
39.399 + * @see #DECEMBER
39.400 + * @see #UNDECIMBER
39.401 + */
39.402 + public final static int MONTH = 2;
39.403 +
39.404 + /**
39.405 + * Field number for <code>get</code> and <code>set</code> indicating the
39.406 + * week number within the current year. The first week of the year, as
39.407 + * defined by <code>getFirstDayOfWeek()</code> and
39.408 + * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
39.409 + * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
39.410 + * the year.
39.411 + *
39.412 + * @see #getFirstDayOfWeek
39.413 + * @see #getMinimalDaysInFirstWeek
39.414 + */
39.415 + public final static int WEEK_OF_YEAR = 3;
39.416 +
39.417 + /**
39.418 + * Field number for <code>get</code> and <code>set</code> indicating the
39.419 + * week number within the current month. The first week of the month, as
39.420 + * defined by <code>getFirstDayOfWeek()</code> and
39.421 + * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
39.422 + * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
39.423 + * the month.
39.424 + *
39.425 + * @see #getFirstDayOfWeek
39.426 + * @see #getMinimalDaysInFirstWeek
39.427 + */
39.428 + public final static int WEEK_OF_MONTH = 4;
39.429 +
39.430 + /**
39.431 + * Field number for <code>get</code> and <code>set</code> indicating the
39.432 + * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
39.433 + * The first day of the month has value 1.
39.434 + *
39.435 + * @see #DAY_OF_MONTH
39.436 + */
39.437 + public final static int DATE = 5;
39.438 +
39.439 + /**
39.440 + * Field number for <code>get</code> and <code>set</code> indicating the
39.441 + * day of the month. This is a synonym for <code>DATE</code>.
39.442 + * The first day of the month has value 1.
39.443 + *
39.444 + * @see #DATE
39.445 + */
39.446 + public final static int DAY_OF_MONTH = 5;
39.447 +
39.448 + /**
39.449 + * Field number for <code>get</code> and <code>set</code> indicating the day
39.450 + * number within the current year. The first day of the year has value 1.
39.451 + */
39.452 + public final static int DAY_OF_YEAR = 6;
39.453 +
39.454 + /**
39.455 + * Field number for <code>get</code> and <code>set</code> indicating the day
39.456 + * of the week. This field takes values <code>SUNDAY</code>,
39.457 + * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
39.458 + * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
39.459 + *
39.460 + * @see #SUNDAY
39.461 + * @see #MONDAY
39.462 + * @see #TUESDAY
39.463 + * @see #WEDNESDAY
39.464 + * @see #THURSDAY
39.465 + * @see #FRIDAY
39.466 + * @see #SATURDAY
39.467 + */
39.468 + public final static int DAY_OF_WEEK = 7;
39.469 +
39.470 + /**
39.471 + * Field number for <code>get</code> and <code>set</code> indicating the
39.472 + * ordinal number of the day of the week within the current month. Together
39.473 + * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
39.474 + * within a month. Unlike <code>WEEK_OF_MONTH</code> and
39.475 + * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
39.476 + * <code>getFirstDayOfWeek()</code> or
39.477 + * <code>getMinimalDaysInFirstWeek()</code>. <code>DAY_OF_MONTH 1</code>
39.478 + * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
39.479 + * 1</code>; <code>8</code> through <code>14</code> correspond to
39.480 + * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
39.481 + * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
39.482 + * <code>DAY_OF_WEEK_IN_MONTH 1</code>. Negative values count back from the
39.483 + * end of the month, so the last Sunday of a month is specified as
39.484 + * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>. Because
39.485 + * negative values count backward they will usually be aligned differently
39.486 + * within the month than positive values. For example, if a month has 31
39.487 + * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
39.488 + * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
39.489 + *
39.490 + * @see #DAY_OF_WEEK
39.491 + * @see #WEEK_OF_MONTH
39.492 + */
39.493 + public final static int DAY_OF_WEEK_IN_MONTH = 8;
39.494 +
39.495 + /**
39.496 + * Field number for <code>get</code> and <code>set</code> indicating
39.497 + * whether the <code>HOUR</code> is before or after noon.
39.498 + * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
39.499 + *
39.500 + * @see #AM
39.501 + * @see #PM
39.502 + * @see #HOUR
39.503 + */
39.504 + public final static int AM_PM = 9;
39.505 +
39.506 + /**
39.507 + * Field number for <code>get</code> and <code>set</code> indicating the
39.508 + * hour of the morning or afternoon. <code>HOUR</code> is used for the
39.509 + * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
39.510 + * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
39.511 + *
39.512 + * @see #AM_PM
39.513 + * @see #HOUR_OF_DAY
39.514 + */
39.515 + public final static int HOUR = 10;
39.516 +
39.517 + /**
39.518 + * Field number for <code>get</code> and <code>set</code> indicating the
39.519 + * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
39.520 + * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
39.521 + *
39.522 + * @see #HOUR
39.523 + */
39.524 + public final static int HOUR_OF_DAY = 11;
39.525 +
39.526 + /**
39.527 + * Field number for <code>get</code> and <code>set</code> indicating the
39.528 + * minute within the hour.
39.529 + * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
39.530 + */
39.531 + public final static int MINUTE = 12;
39.532 +
39.533 + /**
39.534 + * Field number for <code>get</code> and <code>set</code> indicating the
39.535 + * second within the minute.
39.536 + * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
39.537 + */
39.538 + public final static int SECOND = 13;
39.539 +
39.540 + /**
39.541 + * Field number for <code>get</code> and <code>set</code> indicating the
39.542 + * millisecond within the second.
39.543 + * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
39.544 + */
39.545 + public final static int MILLISECOND = 14;
39.546 +
39.547 + /**
39.548 + * Field number for <code>get</code> and <code>set</code>
39.549 + * indicating the raw offset from GMT in milliseconds.
39.550 + * <p>
39.551 + * This field reflects the correct GMT offset value of the time
39.552 + * zone of this <code>Calendar</code> if the
39.553 + * <code>TimeZone</code> implementation subclass supports
39.554 + * historical GMT offset changes.
39.555 + */
39.556 + public final static int ZONE_OFFSET = 15;
39.557 +
39.558 + /**
39.559 + * Field number for <code>get</code> and <code>set</code> indicating the
39.560 + * daylight saving offset in milliseconds.
39.561 + * <p>
39.562 + * This field reflects the correct daylight saving offset value of
39.563 + * the time zone of this <code>Calendar</code> if the
39.564 + * <code>TimeZone</code> implementation subclass supports
39.565 + * historical Daylight Saving Time schedule changes.
39.566 + */
39.567 + public final static int DST_OFFSET = 16;
39.568 +
39.569 + /**
39.570 + * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
39.571 + * Field numbers range from <code>0..FIELD_COUNT-1</code>.
39.572 + */
39.573 + public final static int FIELD_COUNT = 17;
39.574 +
39.575 + /**
39.576 + * Value of the {@link #DAY_OF_WEEK} field indicating
39.577 + * Sunday.
39.578 + */
39.579 + public final static int SUNDAY = 1;
39.580 +
39.581 + /**
39.582 + * Value of the {@link #DAY_OF_WEEK} field indicating
39.583 + * Monday.
39.584 + */
39.585 + public final static int MONDAY = 2;
39.586 +
39.587 + /**
39.588 + * Value of the {@link #DAY_OF_WEEK} field indicating
39.589 + * Tuesday.
39.590 + */
39.591 + public final static int TUESDAY = 3;
39.592 +
39.593 + /**
39.594 + * Value of the {@link #DAY_OF_WEEK} field indicating
39.595 + * Wednesday.
39.596 + */
39.597 + public final static int WEDNESDAY = 4;
39.598 +
39.599 + /**
39.600 + * Value of the {@link #DAY_OF_WEEK} field indicating
39.601 + * Thursday.
39.602 + */
39.603 + public final static int THURSDAY = 5;
39.604 +
39.605 + /**
39.606 + * Value of the {@link #DAY_OF_WEEK} field indicating
39.607 + * Friday.
39.608 + */
39.609 + public final static int FRIDAY = 6;
39.610 +
39.611 + /**
39.612 + * Value of the {@link #DAY_OF_WEEK} field indicating
39.613 + * Saturday.
39.614 + */
39.615 + public final static int SATURDAY = 7;
39.616 +
39.617 + /**
39.618 + * Value of the {@link #MONTH} field indicating the
39.619 + * first month of the year in the Gregorian and Julian calendars.
39.620 + */
39.621 + public final static int JANUARY = 0;
39.622 +
39.623 + /**
39.624 + * Value of the {@link #MONTH} field indicating the
39.625 + * second month of the year in the Gregorian and Julian calendars.
39.626 + */
39.627 + public final static int FEBRUARY = 1;
39.628 +
39.629 + /**
39.630 + * Value of the {@link #MONTH} field indicating the
39.631 + * third month of the year in the Gregorian and Julian calendars.
39.632 + */
39.633 + public final static int MARCH = 2;
39.634 +
39.635 + /**
39.636 + * Value of the {@link #MONTH} field indicating the
39.637 + * fourth month of the year in the Gregorian and Julian calendars.
39.638 + */
39.639 + public final static int APRIL = 3;
39.640 +
39.641 + /**
39.642 + * Value of the {@link #MONTH} field indicating the
39.643 + * fifth month of the year in the Gregorian and Julian calendars.
39.644 + */
39.645 + public final static int MAY = 4;
39.646 +
39.647 + /**
39.648 + * Value of the {@link #MONTH} field indicating the
39.649 + * sixth month of the year in the Gregorian and Julian calendars.
39.650 + */
39.651 + public final static int JUNE = 5;
39.652 +
39.653 + /**
39.654 + * Value of the {@link #MONTH} field indicating the
39.655 + * seventh month of the year in the Gregorian and Julian calendars.
39.656 + */
39.657 + public final static int JULY = 6;
39.658 +
39.659 + /**
39.660 + * Value of the {@link #MONTH} field indicating the
39.661 + * eighth month of the year in the Gregorian and Julian calendars.
39.662 + */
39.663 + public final static int AUGUST = 7;
39.664 +
39.665 + /**
39.666 + * Value of the {@link #MONTH} field indicating the
39.667 + * ninth month of the year in the Gregorian and Julian calendars.
39.668 + */
39.669 + public final static int SEPTEMBER = 8;
39.670 +
39.671 + /**
39.672 + * Value of the {@link #MONTH} field indicating the
39.673 + * tenth month of the year in the Gregorian and Julian calendars.
39.674 + */
39.675 + public final static int OCTOBER = 9;
39.676 +
39.677 + /**
39.678 + * Value of the {@link #MONTH} field indicating the
39.679 + * eleventh month of the year in the Gregorian and Julian calendars.
39.680 + */
39.681 + public final static int NOVEMBER = 10;
39.682 +
39.683 + /**
39.684 + * Value of the {@link #MONTH} field indicating the
39.685 + * twelfth month of the year in the Gregorian and Julian calendars.
39.686 + */
39.687 + public final static int DECEMBER = 11;
39.688 +
39.689 + /**
39.690 + * Value of the {@link #MONTH} field indicating the
39.691 + * thirteenth month of the year. Although <code>GregorianCalendar</code>
39.692 + * does not use this value, lunar calendars do.
39.693 + */
39.694 + public final static int UNDECIMBER = 12;
39.695 +
39.696 + /**
39.697 + * Value of the {@link #AM_PM} field indicating the
39.698 + * period of the day from midnight to just before noon.
39.699 + */
39.700 + public final static int AM = 0;
39.701 +
39.702 + /**
39.703 + * Value of the {@link #AM_PM} field indicating the
39.704 + * period of the day from noon to just before midnight.
39.705 + */
39.706 + public final static int PM = 1;
39.707 +
39.708 + /**
39.709 + * A style specifier for {@link #getDisplayNames(int, int, Locale)
39.710 + * getDisplayNames} indicating names in all styles, such as
39.711 + * "January" and "Jan".
39.712 + *
39.713 + * @see #SHORT
39.714 + * @see #LONG
39.715 + * @since 1.6
39.716 + */
39.717 + public static final int ALL_STYLES = 0;
39.718 +
39.719 + /**
39.720 + * A style specifier for {@link #getDisplayName(int, int, Locale)
39.721 + * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
39.722 + * getDisplayNames} indicating a short name, such as "Jan".
39.723 + *
39.724 + * @see #LONG
39.725 + * @since 1.6
39.726 + */
39.727 + public static final int SHORT = 1;
39.728 +
39.729 + /**
39.730 + * A style specifier for {@link #getDisplayName(int, int, Locale)
39.731 + * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
39.732 + * getDisplayNames} indicating a long name, such as "January".
39.733 + *
39.734 + * @see #SHORT
39.735 + * @since 1.6
39.736 + */
39.737 + public static final int LONG = 2;
39.738 +
39.739 + // Internal notes:
39.740 + // Calendar contains two kinds of time representations: current "time" in
39.741 + // milliseconds, and a set of calendar "fields" representing the current time.
39.742 + // The two representations are usually in sync, but can get out of sync
39.743 + // as follows.
39.744 + // 1. Initially, no fields are set, and the time is invalid.
39.745 + // 2. If the time is set, all fields are computed and in sync.
39.746 + // 3. If a single field is set, the time is invalid.
39.747 + // Recomputation of the time and fields happens when the object needs
39.748 + // to return a result to the user, or use a result for a computation.
39.749 +
39.750 + /**
39.751 + * The calendar field values for the currently set time for this calendar.
39.752 + * This is an array of <code>FIELD_COUNT</code> integers, with index values
39.753 + * <code>ERA</code> through <code>DST_OFFSET</code>.
39.754 + * @serial
39.755 + */
39.756 + protected int fields[];
39.757 +
39.758 + /**
39.759 + * The flags which tell if a specified calendar field for the calendar is set.
39.760 + * A new object has no fields set. After the first call to a method
39.761 + * which generates the fields, they all remain set after that.
39.762 + * This is an array of <code>FIELD_COUNT</code> booleans, with index values
39.763 + * <code>ERA</code> through <code>DST_OFFSET</code>.
39.764 + * @serial
39.765 + */
39.766 + protected boolean isSet[];
39.767 +
39.768 + /**
39.769 + * Pseudo-time-stamps which specify when each field was set. There
39.770 + * are two special values, UNSET and COMPUTED. Values from
39.771 + * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
39.772 + */
39.773 + transient private int stamp[];
39.774 +
39.775 + /**
39.776 + * The currently set time for this calendar, expressed in milliseconds after
39.777 + * January 1, 1970, 0:00:00 GMT.
39.778 + * @see #isTimeSet
39.779 + * @serial
39.780 + */
39.781 + protected long time;
39.782 +
39.783 + /**
39.784 + * True if then the value of <code>time</code> is valid.
39.785 + * The time is made invalid by a change to an item of <code>field[]</code>.
39.786 + * @see #time
39.787 + * @serial
39.788 + */
39.789 + protected boolean isTimeSet;
39.790 +
39.791 + /**
39.792 + * True if <code>fields[]</code> are in sync with the currently set time.
39.793 + * If false, then the next attempt to get the value of a field will
39.794 + * force a recomputation of all fields from the current value of
39.795 + * <code>time</code>.
39.796 + * @serial
39.797 + */
39.798 + protected boolean areFieldsSet;
39.799 +
39.800 + /**
39.801 + * True if all fields have been set.
39.802 + * @serial
39.803 + */
39.804 + transient boolean areAllFieldsSet;
39.805 +
39.806 + /**
39.807 + * <code>True</code> if this calendar allows out-of-range field values during computation
39.808 + * of <code>time</code> from <code>fields[]</code>.
39.809 + * @see #setLenient
39.810 + * @see #isLenient
39.811 + * @serial
39.812 + */
39.813 + private boolean lenient = true;
39.814 +
39.815 + /**
39.816 + * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
39.817 + * uses the time zone data to translate between locale and GMT time.
39.818 + * @serial
39.819 + */
39.820 + private TimeZone zone;
39.821 +
39.822 + /**
39.823 + * <code>True</code> if zone references to a shared TimeZone object.
39.824 + */
39.825 + transient private boolean sharedZone = false;
39.826 +
39.827 + /**
39.828 + * The first day of the week, with possible values <code>SUNDAY</code>,
39.829 + * <code>MONDAY</code>, etc. This is a locale-dependent value.
39.830 + * @serial
39.831 + */
39.832 + private int firstDayOfWeek;
39.833 +
39.834 + /**
39.835 + * The number of days required for the first week in a month or year,
39.836 + * with possible values from 1 to 7. This is a locale-dependent value.
39.837 + * @serial
39.838 + */
39.839 + private int minimalDaysInFirstWeek;
39.840 +
39.841 + /**
39.842 + * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
39.843 + * of a Locale.
39.844 + */
39.845 + private static final ConcurrentMap<Locale, int[]> cachedLocaleData
39.846 + = new ConcurrentHashMap<Locale, int[]>(3);
39.847 +
39.848 + // Special values of stamp[]
39.849 + /**
39.850 + * The corresponding fields[] has no value.
39.851 + */
39.852 + private static final int UNSET = 0;
39.853 +
39.854 + /**
39.855 + * The value of the corresponding fields[] has been calculated internally.
39.856 + */
39.857 + private static final int COMPUTED = 1;
39.858 +
39.859 + /**
39.860 + * The value of the corresponding fields[] has been set externally. Stamp
39.861 + * values which are greater than 1 represents the (pseudo) time when the
39.862 + * corresponding fields[] value was set.
39.863 + */
39.864 + private static final int MINIMUM_USER_STAMP = 2;
39.865 +
39.866 + /**
39.867 + * The mask value that represents all of the fields.
39.868 + */
39.869 + static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
39.870 +
39.871 + /**
39.872 + * The next available value for <code>stamp[]</code>, an internal array.
39.873 + * This actually should not be written out to the stream, and will probably
39.874 + * be removed from the stream in the near future. In the meantime,
39.875 + * a value of <code>MINIMUM_USER_STAMP</code> should be used.
39.876 + * @serial
39.877 + */
39.878 + private int nextStamp = MINIMUM_USER_STAMP;
39.879 +
39.880 + // the internal serial version which says which version was written
39.881 + // - 0 (default) for version up to JDK 1.1.5
39.882 + // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
39.883 + // as well as compatible values for other fields. This is a
39.884 + // transitional format.
39.885 + // - 2 (not implemented yet) a future version, in which fields[],
39.886 + // areFieldsSet, and isTimeSet become transient, and isSet[] is
39.887 + // removed. In JDK 1.1.6 we write a format compatible with version 2.
39.888 + static final int currentSerialVersion = 1;
39.889 +
39.890 + /**
39.891 + * The version of the serialized data on the stream. Possible values:
39.892 + * <dl>
39.893 + * <dt><b>0</b> or not present on stream</dt>
39.894 + * <dd>
39.895 + * JDK 1.1.5 or earlier.
39.896 + * </dd>
39.897 + * <dt><b>1</b></dt>
39.898 + * <dd>
39.899 + * JDK 1.1.6 or later. Writes a correct 'time' value
39.900 + * as well as compatible values for other fields. This is a
39.901 + * transitional format.
39.902 + * </dd>
39.903 + * </dl>
39.904 + * When streaming out this class, the most recent format
39.905 + * and the highest allowable <code>serialVersionOnStream</code>
39.906 + * is written.
39.907 + * @serial
39.908 + * @since JDK1.1.6
39.909 + */
39.910 + private int serialVersionOnStream = currentSerialVersion;
39.911 +
39.912 + // Proclaim serialization compatibility with JDK 1.1
39.913 + static final long serialVersionUID = -1807547505821590642L;
39.914 +
39.915 + // Mask values for calendar fields
39.916 + final static int ERA_MASK = (1 << ERA);
39.917 + final static int YEAR_MASK = (1 << YEAR);
39.918 + final static int MONTH_MASK = (1 << MONTH);
39.919 + final static int WEEK_OF_YEAR_MASK = (1 << WEEK_OF_YEAR);
39.920 + final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
39.921 + final static int DAY_OF_MONTH_MASK = (1 << DAY_OF_MONTH);
39.922 + final static int DATE_MASK = DAY_OF_MONTH_MASK;
39.923 + final static int DAY_OF_YEAR_MASK = (1 << DAY_OF_YEAR);
39.924 + final static int DAY_OF_WEEK_MASK = (1 << DAY_OF_WEEK);
39.925 + final static int DAY_OF_WEEK_IN_MONTH_MASK = (1 << DAY_OF_WEEK_IN_MONTH);
39.926 + final static int AM_PM_MASK = (1 << AM_PM);
39.927 + final static int HOUR_MASK = (1 << HOUR);
39.928 + final static int HOUR_OF_DAY_MASK = (1 << HOUR_OF_DAY);
39.929 + final static int MINUTE_MASK = (1 << MINUTE);
39.930 + final static int SECOND_MASK = (1 << SECOND);
39.931 + final static int MILLISECOND_MASK = (1 << MILLISECOND);
39.932 + final static int ZONE_OFFSET_MASK = (1 << ZONE_OFFSET);
39.933 + final static int DST_OFFSET_MASK = (1 << DST_OFFSET);
39.934 +
39.935 + /**
39.936 + * Constructs a Calendar with the default time zone
39.937 + * and locale.
39.938 + * @see TimeZone#getDefault
39.939 + */
39.940 + protected Calendar()
39.941 + {
39.942 + this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
39.943 + sharedZone = true;
39.944 + }
39.945 +
39.946 + /**
39.947 + * Constructs a calendar with the specified time zone and locale.
39.948 + *
39.949 + * @param zone the time zone to use
39.950 + * @param aLocale the locale for the week data
39.951 + */
39.952 + protected Calendar(TimeZone zone, Locale aLocale)
39.953 + {
39.954 + fields = new int[FIELD_COUNT];
39.955 + isSet = new boolean[FIELD_COUNT];
39.956 + stamp = new int[FIELD_COUNT];
39.957 +
39.958 + this.zone = zone;
39.959 + setWeekCountData(aLocale);
39.960 + }
39.961 +
39.962 + /**
39.963 + * Gets a calendar using the default time zone and locale. The
39.964 + * <code>Calendar</code> returned is based on the current time
39.965 + * in the default time zone with the default locale.
39.966 + *
39.967 + * @return a Calendar.
39.968 + */
39.969 + public static Calendar getInstance()
39.970 + {
39.971 + Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
39.972 + cal.sharedZone = true;
39.973 + return cal;
39.974 + }
39.975 +
39.976 + /**
39.977 + * Gets a calendar using the specified time zone and default locale.
39.978 + * The <code>Calendar</code> returned is based on the current time
39.979 + * in the given time zone with the default locale.
39.980 + *
39.981 + * @param zone the time zone to use
39.982 + * @return a Calendar.
39.983 + */
39.984 + public static Calendar getInstance(TimeZone zone)
39.985 + {
39.986 + return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
39.987 + }
39.988 +
39.989 + /**
39.990 + * Gets a calendar using the default time zone and specified locale.
39.991 + * The <code>Calendar</code> returned is based on the current time
39.992 + * in the default time zone with the given locale.
39.993 + *
39.994 + * @param aLocale the locale for the week data
39.995 + * @return a Calendar.
39.996 + */
39.997 + public static Calendar getInstance(Locale aLocale)
39.998 + {
39.999 + Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale);
39.1000 + cal.sharedZone = true;
39.1001 + return cal;
39.1002 + }
39.1003 +
39.1004 + /**
39.1005 + * Gets a calendar with the specified time zone and locale.
39.1006 + * The <code>Calendar</code> returned is based on the current time
39.1007 + * in the given time zone with the given locale.
39.1008 + *
39.1009 + * @param zone the time zone to use
39.1010 + * @param aLocale the locale for the week data
39.1011 + * @return a Calendar.
39.1012 + */
39.1013 + public static Calendar getInstance(TimeZone zone,
39.1014 + Locale aLocale)
39.1015 + {
39.1016 + return createCalendar(zone, aLocale);
39.1017 + }
39.1018 +
39.1019 + private static Calendar createCalendar(TimeZone zone,
39.1020 + Locale aLocale)
39.1021 + {
39.1022 + Calendar cal = null;
39.1023 +
39.1024 + String caltype = aLocale.getUnicodeLocaleType("ca");
39.1025 + if (caltype == null) {
39.1026 + // Calendar type is not specified.
39.1027 + // If the specified locale is a Thai locale,
39.1028 + // returns a BuddhistCalendar instance.
39.1029 + if ("th".equals(aLocale.getLanguage())
39.1030 + && ("TH".equals(aLocale.getCountry()))) {
39.1031 + cal = new BuddhistCalendar(zone, aLocale);
39.1032 + } else {
39.1033 + cal = new GregorianCalendar(zone, aLocale);
39.1034 + }
39.1035 + } else if (caltype.equals("japanese")) {
39.1036 + cal = new JapaneseImperialCalendar(zone, aLocale);
39.1037 + } else if (caltype.equals("buddhist")) {
39.1038 + cal = new BuddhistCalendar(zone, aLocale);
39.1039 + } else {
39.1040 + // Unsupported calendar type.
39.1041 + // Use Gregorian calendar as a fallback.
39.1042 + cal = new GregorianCalendar(zone, aLocale);
39.1043 + }
39.1044 +
39.1045 + return cal;
39.1046 + }
39.1047 +
39.1048 + /**
39.1049 + * Returns an array of all locales for which the <code>getInstance</code>
39.1050 + * methods of this class can return localized instances.
39.1051 + * The array returned must contain at least a <code>Locale</code>
39.1052 + * instance equal to {@link java.util.Locale#US Locale.US}.
39.1053 + *
39.1054 + * @return An array of locales for which localized
39.1055 + * <code>Calendar</code> instances are available.
39.1056 + */
39.1057 + public static synchronized Locale[] getAvailableLocales()
39.1058 + {
39.1059 + return DateFormat.getAvailableLocales();
39.1060 + }
39.1061 +
39.1062 + /**
39.1063 + * Converts the current calendar field values in {@link #fields fields[]}
39.1064 + * to the millisecond time value
39.1065 + * {@link #time}.
39.1066 + *
39.1067 + * @see #complete()
39.1068 + * @see #computeFields()
39.1069 + */
39.1070 + protected abstract void computeTime();
39.1071 +
39.1072 + /**
39.1073 + * Converts the current millisecond time value {@link #time}
39.1074 + * to calendar field values in {@link #fields fields[]}.
39.1075 + * This allows you to sync up the calendar field values with
39.1076 + * a new time that is set for the calendar. The time is <em>not</em>
39.1077 + * recomputed first; to recompute the time, then the fields, call the
39.1078 + * {@link #complete()} method.
39.1079 + *
39.1080 + * @see #computeTime()
39.1081 + */
39.1082 + protected abstract void computeFields();
39.1083 +
39.1084 + /**
39.1085 + * Returns a <code>Date</code> object representing this
39.1086 + * <code>Calendar</code>'s time value (millisecond offset from the <a
39.1087 + * href="#Epoch">Epoch</a>").
39.1088 + *
39.1089 + * @return a <code>Date</code> representing the time value.
39.1090 + * @see #setTime(Date)
39.1091 + * @see #getTimeInMillis()
39.1092 + */
39.1093 + public final Date getTime() {
39.1094 + return new Date(getTimeInMillis());
39.1095 + }
39.1096 +
39.1097 + /**
39.1098 + * Sets this Calendar's time with the given <code>Date</code>.
39.1099 + * <p>
39.1100 + * Note: Calling <code>setTime()</code> with
39.1101 + * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
39.1102 + * may yield incorrect field values from <code>get()</code>.
39.1103 + *
39.1104 + * @param date the given Date.
39.1105 + * @see #getTime()
39.1106 + * @see #setTimeInMillis(long)
39.1107 + */
39.1108 + public final void setTime(Date date) {
39.1109 + setTimeInMillis(date.getTime());
39.1110 + }
39.1111 +
39.1112 + /**
39.1113 + * Returns this Calendar's time value in milliseconds.
39.1114 + *
39.1115 + * @return the current time as UTC milliseconds from the epoch.
39.1116 + * @see #getTime()
39.1117 + * @see #setTimeInMillis(long)
39.1118 + */
39.1119 + public long getTimeInMillis() {
39.1120 + if (!isTimeSet) {
39.1121 + updateTime();
39.1122 + }
39.1123 + return time;
39.1124 + }
39.1125 +
39.1126 + /**
39.1127 + * Sets this Calendar's current time from the given long value.
39.1128 + *
39.1129 + * @param millis the new time in UTC milliseconds from the epoch.
39.1130 + * @see #setTime(Date)
39.1131 + * @see #getTimeInMillis()
39.1132 + */
39.1133 + public void setTimeInMillis(long millis) {
39.1134 + // If we don't need to recalculate the calendar field values,
39.1135 + // do nothing.
39.1136 + if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
39.1137 + && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
39.1138 + return;
39.1139 + }
39.1140 + time = millis;
39.1141 + isTimeSet = true;
39.1142 + areFieldsSet = false;
39.1143 + computeFields();
39.1144 + areAllFieldsSet = areFieldsSet = true;
39.1145 + }
39.1146 +
39.1147 + /**
39.1148 + * Returns the value of the given calendar field. In lenient mode,
39.1149 + * all calendar fields are normalized. In non-lenient mode, all
39.1150 + * calendar fields are validated and this method throws an
39.1151 + * exception if any calendar fields have out-of-range values. The
39.1152 + * normalization and validation are handled by the
39.1153 + * {@link #complete()} method, which process is calendar
39.1154 + * system dependent.
39.1155 + *
39.1156 + * @param field the given calendar field.
39.1157 + * @return the value for the given calendar field.
39.1158 + * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
39.1159 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
39.1160 + * @see #set(int,int)
39.1161 + * @see #complete()
39.1162 + */
39.1163 + public int get(int field)
39.1164 + {
39.1165 + complete();
39.1166 + return internalGet(field);
39.1167 + }
39.1168 +
39.1169 + /**
39.1170 + * Returns the value of the given calendar field. This method does
39.1171 + * not involve normalization or validation of the field value.
39.1172 + *
39.1173 + * @param field the given calendar field.
39.1174 + * @return the value for the given calendar field.
39.1175 + * @see #get(int)
39.1176 + */
39.1177 + protected final int internalGet(int field)
39.1178 + {
39.1179 + return fields[field];
39.1180 + }
39.1181 +
39.1182 + /**
39.1183 + * Sets the value of the given calendar field. This method does
39.1184 + * not affect any setting state of the field in this
39.1185 + * <code>Calendar</code> instance.
39.1186 + *
39.1187 + * @throws IndexOutOfBoundsException if the specified field is out of range
39.1188 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
39.1189 + * @see #areFieldsSet
39.1190 + * @see #isTimeSet
39.1191 + * @see #areAllFieldsSet
39.1192 + * @see #set(int,int)
39.1193 + */
39.1194 + final void internalSet(int field, int value)
39.1195 + {
39.1196 + fields[field] = value;
39.1197 + }
39.1198 +
39.1199 + /**
39.1200 + * Sets the given calendar field to the given value. The value is not
39.1201 + * interpreted by this method regardless of the leniency mode.
39.1202 + *
39.1203 + * @param field the given calendar field.
39.1204 + * @param value the value to be set for the given calendar field.
39.1205 + * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
39.1206 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
39.1207 + * in non-lenient mode.
39.1208 + * @see #set(int,int,int)
39.1209 + * @see #set(int,int,int,int,int)
39.1210 + * @see #set(int,int,int,int,int,int)
39.1211 + * @see #get(int)
39.1212 + */
39.1213 + public void set(int field, int value)
39.1214 + {
39.1215 + // If the fields are partially normalized, calculate all the
39.1216 + // fields before changing any fields.
39.1217 + if (areFieldsSet && !areAllFieldsSet) {
39.1218 + computeFields();
39.1219 + }
39.1220 + internalSet(field, value);
39.1221 + isTimeSet = false;
39.1222 + areFieldsSet = false;
39.1223 + isSet[field] = true;
39.1224 + stamp[field] = nextStamp++;
39.1225 + if (nextStamp == Integer.MAX_VALUE) {
39.1226 + adjustStamp();
39.1227 + }
39.1228 + }
39.1229 +
39.1230 + /**
39.1231 + * Sets the values for the calendar fields <code>YEAR</code>,
39.1232 + * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
39.1233 + * Previous values of other calendar fields are retained. If this is not desired,
39.1234 + * call {@link #clear()} first.
39.1235 + *
39.1236 + * @param year the value used to set the <code>YEAR</code> calendar field.
39.1237 + * @param month the value used to set the <code>MONTH</code> calendar field.
39.1238 + * Month value is 0-based. e.g., 0 for January.
39.1239 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
39.1240 + * @see #set(int,int)
39.1241 + * @see #set(int,int,int,int,int)
39.1242 + * @see #set(int,int,int,int,int,int)
39.1243 + */
39.1244 + public final void set(int year, int month, int date)
39.1245 + {
39.1246 + set(YEAR, year);
39.1247 + set(MONTH, month);
39.1248 + set(DATE, date);
39.1249 + }
39.1250 +
39.1251 + /**
39.1252 + * Sets the values for the calendar fields <code>YEAR</code>,
39.1253 + * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
39.1254 + * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
39.1255 + * Previous values of other fields are retained. If this is not desired,
39.1256 + * call {@link #clear()} first.
39.1257 + *
39.1258 + * @param year the value used to set the <code>YEAR</code> calendar field.
39.1259 + * @param month the value used to set the <code>MONTH</code> calendar field.
39.1260 + * Month value is 0-based. e.g., 0 for January.
39.1261 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
39.1262 + * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
39.1263 + * @param minute the value used to set the <code>MINUTE</code> calendar field.
39.1264 + * @see #set(int,int)
39.1265 + * @see #set(int,int,int)
39.1266 + * @see #set(int,int,int,int,int,int)
39.1267 + */
39.1268 + public final void set(int year, int month, int date, int hourOfDay, int minute)
39.1269 + {
39.1270 + set(YEAR, year);
39.1271 + set(MONTH, month);
39.1272 + set(DATE, date);
39.1273 + set(HOUR_OF_DAY, hourOfDay);
39.1274 + set(MINUTE, minute);
39.1275 + }
39.1276 +
39.1277 + /**
39.1278 + * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
39.1279 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, <code>MINUTE</code>, and
39.1280 + * <code>SECOND</code>.
39.1281 + * Previous values of other fields are retained. If this is not desired,
39.1282 + * call {@link #clear()} first.
39.1283 + *
39.1284 + * @param year the value used to set the <code>YEAR</code> calendar field.
39.1285 + * @param month the value used to set the <code>MONTH</code> calendar field.
39.1286 + * Month value is 0-based. e.g., 0 for January.
39.1287 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
39.1288 + * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
39.1289 + * @param minute the value used to set the <code>MINUTE</code> calendar field.
39.1290 + * @param second the value used to set the <code>SECOND</code> calendar field.
39.1291 + * @see #set(int,int)
39.1292 + * @see #set(int,int,int)
39.1293 + * @see #set(int,int,int,int,int)
39.1294 + */
39.1295 + public final void set(int year, int month, int date, int hourOfDay, int minute,
39.1296 + int second)
39.1297 + {
39.1298 + set(YEAR, year);
39.1299 + set(MONTH, month);
39.1300 + set(DATE, date);
39.1301 + set(HOUR_OF_DAY, hourOfDay);
39.1302 + set(MINUTE, minute);
39.1303 + set(SECOND, second);
39.1304 + }
39.1305 +
39.1306 + /**
39.1307 + * Sets all the calendar field values and the time value
39.1308 + * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
39.1309 + * this <code>Calendar</code> undefined. This means that {@link
39.1310 + * #isSet(int) isSet()} will return <code>false</code> for all the
39.1311 + * calendar fields, and the date and time calculations will treat
39.1312 + * the fields as if they had never been set. A
39.1313 + * <code>Calendar</code> implementation class may use its specific
39.1314 + * default field values for date/time calculations. For example,
39.1315 + * <code>GregorianCalendar</code> uses 1970 if the
39.1316 + * <code>YEAR</code> field value is undefined.
39.1317 + *
39.1318 + * @see #clear(int)
39.1319 + */
39.1320 + public final void clear()
39.1321 + {
39.1322 + for (int i = 0; i < fields.length; ) {
39.1323 + stamp[i] = fields[i] = 0; // UNSET == 0
39.1324 + isSet[i++] = false;
39.1325 + }
39.1326 + areAllFieldsSet = areFieldsSet = false;
39.1327 + isTimeSet = false;
39.1328 + }
39.1329 +
39.1330 + /**
39.1331 + * Sets the given calendar field value and the time value
39.1332 + * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
39.1333 + * this <code>Calendar</code> undefined. This means that {@link
39.1334 + * #isSet(int) isSet(field)} will return <code>false</code>, and
39.1335 + * the date and time calculations will treat the field as if it
39.1336 + * had never been set. A <code>Calendar</code> implementation
39.1337 + * class may use the field's specific default value for date and
39.1338 + * time calculations.
39.1339 + *
39.1340 + * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
39.1341 + * fields are handled independently and the <a
39.1342 + * href="#time_resolution">the resolution rule for the time of
39.1343 + * day</a> is applied. Clearing one of the fields doesn't reset
39.1344 + * the hour of day value of this <code>Calendar</code>. Use {@link
39.1345 + * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
39.1346 + * value.
39.1347 + *
39.1348 + * @param field the calendar field to be cleared.
39.1349 + * @see #clear()
39.1350 + */
39.1351 + public final void clear(int field)
39.1352 + {
39.1353 + fields[field] = 0;
39.1354 + stamp[field] = UNSET;
39.1355 + isSet[field] = false;
39.1356 +
39.1357 + areAllFieldsSet = areFieldsSet = false;
39.1358 + isTimeSet = false;
39.1359 + }
39.1360 +
39.1361 + /**
39.1362 + * Determines if the given calendar field has a value set,
39.1363 + * including cases that the value has been set by internal fields
39.1364 + * calculations triggered by a <code>get</code> method call.
39.1365 + *
39.1366 + * @return <code>true</code> if the given calendar field has a value set;
39.1367 + * <code>false</code> otherwise.
39.1368 + */
39.1369 + public final boolean isSet(int field)
39.1370 + {
39.1371 + return stamp[field] != UNSET;
39.1372 + }
39.1373 +
39.1374 + /**
39.1375 + * Returns the string representation of the calendar
39.1376 + * <code>field</code> value in the given <code>style</code> and
39.1377 + * <code>locale</code>. If no string representation is
39.1378 + * applicable, <code>null</code> is returned. This method calls
39.1379 + * {@link Calendar#get(int) get(field)} to get the calendar
39.1380 + * <code>field</code> value if the string representation is
39.1381 + * applicable to the given calendar <code>field</code>.
39.1382 + *
39.1383 + * <p>For example, if this <code>Calendar</code> is a
39.1384 + * <code>GregorianCalendar</code> and its date is 2005-01-01, then
39.1385 + * the string representation of the {@link #MONTH} field would be
39.1386 + * "January" in the long style in an English locale or "Jan" in
39.1387 + * the short style. However, no string representation would be
39.1388 + * available for the {@link #DAY_OF_MONTH} field, and this method
39.1389 + * would return <code>null</code>.
39.1390 + *
39.1391 + * <p>The default implementation supports the calendar fields for
39.1392 + * which a {@link DateFormatSymbols} has names in the given
39.1393 + * <code>locale</code>.
39.1394 + *
39.1395 + * @param field
39.1396 + * the calendar field for which the string representation
39.1397 + * is returned
39.1398 + * @param style
39.1399 + * the style applied to the string representation; one of
39.1400 + * {@link #SHORT} or {@link #LONG}.
39.1401 + * @param locale
39.1402 + * the locale for the string representation
39.1403 + * @return the string representation of the given
39.1404 + * <code>field</code> in the given <code>style</code>, or
39.1405 + * <code>null</code> if no string representation is
39.1406 + * applicable.
39.1407 + * @exception IllegalArgumentException
39.1408 + * if <code>field</code> or <code>style</code> is invalid,
39.1409 + * or if this <code>Calendar</code> is non-lenient and any
39.1410 + * of the calendar fields have invalid values
39.1411 + * @exception NullPointerException
39.1412 + * if <code>locale</code> is null
39.1413 + * @since 1.6
39.1414 + */
39.1415 + public String getDisplayName(int field, int style, Locale locale) {
39.1416 + if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
39.1417 + ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
39.1418 + return null;
39.1419 + }
39.1420 +
39.1421 + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
39.1422 + String[] strings = getFieldStrings(field, style, symbols);
39.1423 + if (strings != null) {
39.1424 + int fieldValue = get(field);
39.1425 + if (fieldValue < strings.length) {
39.1426 + return strings[fieldValue];
39.1427 + }
39.1428 + }
39.1429 + return null;
39.1430 + }
39.1431 +
39.1432 + /**
39.1433 + * Returns a <code>Map</code> containing all names of the calendar
39.1434 + * <code>field</code> in the given <code>style</code> and
39.1435 + * <code>locale</code> and their corresponding field values. For
39.1436 + * example, if this <code>Calendar</code> is a {@link
39.1437 + * GregorianCalendar}, the returned map would contain "Jan" to
39.1438 + * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
39.1439 + * {@linkplain #SHORT short} style in an English locale.
39.1440 + *
39.1441 + * <p>The values of other calendar fields may be taken into
39.1442 + * account to determine a set of display names. For example, if
39.1443 + * this <code>Calendar</code> is a lunisolar calendar system and
39.1444 + * the year value given by the {@link #YEAR} field has a leap
39.1445 + * month, this method would return month names containing the leap
39.1446 + * month name, and month names are mapped to their values specific
39.1447 + * for the year.
39.1448 + *
39.1449 + * <p>The default implementation supports display names contained in
39.1450 + * a {@link DateFormatSymbols}. For example, if <code>field</code>
39.1451 + * is {@link #MONTH} and <code>style</code> is {@link
39.1452 + * #ALL_STYLES}, this method returns a <code>Map</code> containing
39.1453 + * all strings returned by {@link DateFormatSymbols#getShortMonths()}
39.1454 + * and {@link DateFormatSymbols#getMonths()}.
39.1455 + *
39.1456 + * @param field
39.1457 + * the calendar field for which the display names are returned
39.1458 + * @param style
39.1459 + * the style applied to the display names; one of {@link
39.1460 + * #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}.
39.1461 + * @param locale
39.1462 + * the locale for the display names
39.1463 + * @return a <code>Map</code> containing all display names in
39.1464 + * <code>style</code> and <code>locale</code> and their
39.1465 + * field values, or <code>null</code> if no display names
39.1466 + * are defined for <code>field</code>
39.1467 + * @exception IllegalArgumentException
39.1468 + * if <code>field</code> or <code>style</code> is invalid,
39.1469 + * or if this <code>Calendar</code> is non-lenient and any
39.1470 + * of the calendar fields have invalid values
39.1471 + * @exception NullPointerException
39.1472 + * if <code>locale</code> is null
39.1473 + * @since 1.6
39.1474 + */
39.1475 + public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
39.1476 + if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
39.1477 + ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
39.1478 + return null;
39.1479 + }
39.1480 +
39.1481 + // ALL_STYLES
39.1482 + if (style == ALL_STYLES) {
39.1483 + Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
39.1484 + if (field == ERA || field == AM_PM) {
39.1485 + return shortNames;
39.1486 + }
39.1487 + Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale);
39.1488 + if (shortNames == null) {
39.1489 + return longNames;
39.1490 + }
39.1491 + if (longNames != null) {
39.1492 + shortNames.putAll(longNames);
39.1493 + }
39.1494 + return shortNames;
39.1495 + }
39.1496 +
39.1497 + // SHORT or LONG
39.1498 + return getDisplayNamesImpl(field, style, locale);
39.1499 + }
39.1500 +
39.1501 + private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
39.1502 + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
39.1503 + String[] strings = getFieldStrings(field, style, symbols);
39.1504 + if (strings != null) {
39.1505 + Map<String,Integer> names = new HashMap<String,Integer>();
39.1506 + for (int i = 0; i < strings.length; i++) {
39.1507 + if (strings[i].length() == 0) {
39.1508 + continue;
39.1509 + }
39.1510 + names.put(strings[i], i);
39.1511 + }
39.1512 + return names;
39.1513 + }
39.1514 + return null;
39.1515 + }
39.1516 +
39.1517 + boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
39.1518 + Locale locale, int fieldMask) {
39.1519 + if (field < 0 || field >= fields.length ||
39.1520 + style < minStyle || style > maxStyle) {
39.1521 + throw new IllegalArgumentException();
39.1522 + }
39.1523 + if (locale == null) {
39.1524 + throw new NullPointerException();
39.1525 + }
39.1526 + return isFieldSet(fieldMask, field);
39.1527 + }
39.1528 +
39.1529 + private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
39.1530 + String[] strings = null;
39.1531 + switch (field) {
39.1532 + case ERA:
39.1533 + strings = symbols.getEras();
39.1534 + break;
39.1535 +
39.1536 + case MONTH:
39.1537 + strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths();
39.1538 + break;
39.1539 +
39.1540 + case DAY_OF_WEEK:
39.1541 + strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
39.1542 + break;
39.1543 +
39.1544 + case AM_PM:
39.1545 + strings = symbols.getAmPmStrings();
39.1546 + break;
39.1547 + }
39.1548 + return strings;
39.1549 + }
39.1550 +
39.1551 + /**
39.1552 + * Fills in any unset fields in the calendar fields. First, the {@link
39.1553 + * #computeTime()} method is called if the time value (millisecond offset
39.1554 + * from the <a href="#Epoch">Epoch</a>) has not been calculated from
39.1555 + * calendar field values. Then, the {@link #computeFields()} method is
39.1556 + * called to calculate all calendar field values.
39.1557 + */
39.1558 + protected void complete()
39.1559 + {
39.1560 + if (!isTimeSet)
39.1561 + updateTime();
39.1562 + if (!areFieldsSet || !areAllFieldsSet) {
39.1563 + computeFields(); // fills in unset fields
39.1564 + areAllFieldsSet = areFieldsSet = true;
39.1565 + }
39.1566 + }
39.1567 +
39.1568 + /**
39.1569 + * Returns whether the value of the specified calendar field has been set
39.1570 + * externally by calling one of the setter methods rather than by the
39.1571 + * internal time calculation.
39.1572 + *
39.1573 + * @return <code>true</code> if the field has been set externally,
39.1574 + * <code>false</code> otherwise.
39.1575 + * @exception IndexOutOfBoundsException if the specified
39.1576 + * <code>field</code> is out of range
39.1577 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
39.1578 + * @see #selectFields()
39.1579 + * @see #setFieldsComputed(int)
39.1580 + */
39.1581 + final boolean isExternallySet(int field) {
39.1582 + return stamp[field] >= MINIMUM_USER_STAMP;
39.1583 + }
39.1584 +
39.1585 + /**
39.1586 + * Returns a field mask (bit mask) indicating all calendar fields that
39.1587 + * have the state of externally or internally set.
39.1588 + *
39.1589 + * @return a bit mask indicating set state fields
39.1590 + */
39.1591 + final int getSetStateFields() {
39.1592 + int mask = 0;
39.1593 + for (int i = 0; i < fields.length; i++) {
39.1594 + if (stamp[i] != UNSET) {
39.1595 + mask |= 1 << i;
39.1596 + }
39.1597 + }
39.1598 + return mask;
39.1599 + }
39.1600 +
39.1601 + /**
39.1602 + * Sets the state of the specified calendar fields to
39.1603 + * <em>computed</em>. This state means that the specified calendar fields
39.1604 + * have valid values that have been set by internal time calculation
39.1605 + * rather than by calling one of the setter methods.
39.1606 + *
39.1607 + * @param fieldMask the field to be marked as computed.
39.1608 + * @exception IndexOutOfBoundsException if the specified
39.1609 + * <code>field</code> is out of range
39.1610 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
39.1611 + * @see #isExternallySet(int)
39.1612 + * @see #selectFields()
39.1613 + */
39.1614 + final void setFieldsComputed(int fieldMask) {
39.1615 + if (fieldMask == ALL_FIELDS) {
39.1616 + for (int i = 0; i < fields.length; i++) {
39.1617 + stamp[i] = COMPUTED;
39.1618 + isSet[i] = true;
39.1619 + }
39.1620 + areFieldsSet = areAllFieldsSet = true;
39.1621 + } else {
39.1622 + for (int i = 0; i < fields.length; i++) {
39.1623 + if ((fieldMask & 1) == 1) {
39.1624 + stamp[i] = COMPUTED;
39.1625 + isSet[i] = true;
39.1626 + } else {
39.1627 + if (areAllFieldsSet && !isSet[i]) {
39.1628 + areAllFieldsSet = false;
39.1629 + }
39.1630 + }
39.1631 + fieldMask >>>= 1;
39.1632 + }
39.1633 + }
39.1634 + }
39.1635 +
39.1636 + /**
39.1637 + * Sets the state of the calendar fields that are <em>not</em> specified
39.1638 + * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
39.1639 + * specifies all the calendar fields, then the state of this
39.1640 + * <code>Calendar</code> becomes that all the calendar fields are in sync
39.1641 + * with the time value (millisecond offset from the Epoch).
39.1642 + *
39.1643 + * @param fieldMask the field mask indicating which calendar fields are in
39.1644 + * sync with the time value.
39.1645 + * @exception IndexOutOfBoundsException if the specified
39.1646 + * <code>field</code> is out of range
39.1647 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
39.1648 + * @see #isExternallySet(int)
39.1649 + * @see #selectFields()
39.1650 + */
39.1651 + final void setFieldsNormalized(int fieldMask) {
39.1652 + if (fieldMask != ALL_FIELDS) {
39.1653 + for (int i = 0; i < fields.length; i++) {
39.1654 + if ((fieldMask & 1) == 0) {
39.1655 + stamp[i] = fields[i] = 0; // UNSET == 0
39.1656 + isSet[i] = false;
39.1657 + }
39.1658 + fieldMask >>= 1;
39.1659 + }
39.1660 + }
39.1661 +
39.1662 + // Some or all of the fields are in sync with the
39.1663 + // milliseconds, but the stamp values are not normalized yet.
39.1664 + areFieldsSet = true;
39.1665 + areAllFieldsSet = false;
39.1666 + }
39.1667 +
39.1668 + /**
39.1669 + * Returns whether the calendar fields are partially in sync with the time
39.1670 + * value or fully in sync but not stamp values are not normalized yet.
39.1671 + */
39.1672 + final boolean isPartiallyNormalized() {
39.1673 + return areFieldsSet && !areAllFieldsSet;
39.1674 + }
39.1675 +
39.1676 + /**
39.1677 + * Returns whether the calendar fields are fully in sync with the time
39.1678 + * value.
39.1679 + */
39.1680 + final boolean isFullyNormalized() {
39.1681 + return areFieldsSet && areAllFieldsSet;
39.1682 + }
39.1683 +
39.1684 + /**
39.1685 + * Marks this Calendar as not sync'd.
39.1686 + */
39.1687 + final void setUnnormalized() {
39.1688 + areFieldsSet = areAllFieldsSet = false;
39.1689 + }
39.1690 +
39.1691 + /**
39.1692 + * Returns whether the specified <code>field</code> is on in the
39.1693 + * <code>fieldMask</code>.
39.1694 + */
39.1695 + static final boolean isFieldSet(int fieldMask, int field) {
39.1696 + return (fieldMask & (1 << field)) != 0;
39.1697 + }
39.1698 +
39.1699 + /**
39.1700 + * Returns a field mask indicating which calendar field values
39.1701 + * to be used to calculate the time value. The calendar fields are
39.1702 + * returned as a bit mask, each bit of which corresponds to a field, i.e.,
39.1703 + * the mask value of <code>field</code> is <code>(1 <<
39.1704 + * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
39.1705 + * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
39.1706 + * equal to
39.1707 + * <code>(1<<YEAR)|(1<<MONTH)|(1<<DAY_OF_MONTH))</code>.
39.1708 + *
39.1709 + * <p>This method supports the calendar fields resolution as described in
39.1710 + * the class description. If the bit mask for a given field is on and its
39.1711 + * field has not been set (i.e., <code>isSet(field)</code> is
39.1712 + * <code>false</code>), then the default value of the field has to be
39.1713 + * used, which case means that the field has been selected because the
39.1714 + * selected combination involves the field.
39.1715 + *
39.1716 + * @return a bit mask of selected fields
39.1717 + * @see #isExternallySet(int)
39.1718 + * @see #setInternallySetState(int)
39.1719 + */
39.1720 + final int selectFields() {
39.1721 + // This implementation has been taken from the GregorianCalendar class.
39.1722 +
39.1723 + // The YEAR field must always be used regardless of its SET
39.1724 + // state because YEAR is a mandatory field to determine the date
39.1725 + // and the default value (EPOCH_YEAR) may change through the
39.1726 + // normalization process.
39.1727 + int fieldMask = YEAR_MASK;
39.1728 +
39.1729 + if (stamp[ERA] != UNSET) {
39.1730 + fieldMask |= ERA_MASK;
39.1731 + }
39.1732 + // Find the most recent group of fields specifying the day within
39.1733 + // the year. These may be any of the following combinations:
39.1734 + // MONTH + DAY_OF_MONTH
39.1735 + // MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
39.1736 + // MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
39.1737 + // DAY_OF_YEAR
39.1738 + // WEEK_OF_YEAR + DAY_OF_WEEK
39.1739 + // We look for the most recent of the fields in each group to determine
39.1740 + // the age of the group. For groups involving a week-related field such
39.1741 + // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
39.1742 + // week-related field and the DAY_OF_WEEK must be set for the group as a
39.1743 + // whole to be considered. (See bug 4153860 - liu 7/24/98.)
39.1744 + int dowStamp = stamp[DAY_OF_WEEK];
39.1745 + int monthStamp = stamp[MONTH];
39.1746 + int domStamp = stamp[DAY_OF_MONTH];
39.1747 + int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
39.1748 + int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
39.1749 + int doyStamp = stamp[DAY_OF_YEAR];
39.1750 + int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
39.1751 +
39.1752 + int bestStamp = domStamp;
39.1753 + if (womStamp > bestStamp) {
39.1754 + bestStamp = womStamp;
39.1755 + }
39.1756 + if (dowimStamp > bestStamp) {
39.1757 + bestStamp = dowimStamp;
39.1758 + }
39.1759 + if (doyStamp > bestStamp) {
39.1760 + bestStamp = doyStamp;
39.1761 + }
39.1762 + if (woyStamp > bestStamp) {
39.1763 + bestStamp = woyStamp;
39.1764 + }
39.1765 +
39.1766 + /* No complete combination exists. Look for WEEK_OF_MONTH,
39.1767 + * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone. Treat DAY_OF_WEEK alone
39.1768 + * as DAY_OF_WEEK_IN_MONTH.
39.1769 + */
39.1770 + if (bestStamp == UNSET) {
39.1771 + womStamp = stamp[WEEK_OF_MONTH];
39.1772 + dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
39.1773 + woyStamp = stamp[WEEK_OF_YEAR];
39.1774 + bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
39.1775 +
39.1776 + /* Treat MONTH alone or no fields at all as DAY_OF_MONTH. This may
39.1777 + * result in bestStamp = domStamp = UNSET if no fields are set,
39.1778 + * which indicates DAY_OF_MONTH.
39.1779 + */
39.1780 + if (bestStamp == UNSET) {
39.1781 + bestStamp = domStamp = monthStamp;
39.1782 + }
39.1783 + }
39.1784 +
39.1785 + if (bestStamp == domStamp ||
39.1786 + (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
39.1787 + (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
39.1788 + fieldMask |= MONTH_MASK;
39.1789 + if (bestStamp == domStamp) {
39.1790 + fieldMask |= DAY_OF_MONTH_MASK;
39.1791 + } else {
39.1792 + assert (bestStamp == womStamp || bestStamp == dowimStamp);
39.1793 + if (dowStamp != UNSET) {
39.1794 + fieldMask |= DAY_OF_WEEK_MASK;
39.1795 + }
39.1796 + if (womStamp == dowimStamp) {
39.1797 + // When they are equal, give the priority to
39.1798 + // WEEK_OF_MONTH for compatibility.
39.1799 + if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
39.1800 + fieldMask |= WEEK_OF_MONTH_MASK;
39.1801 + } else {
39.1802 + fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
39.1803 + }
39.1804 + } else {
39.1805 + if (bestStamp == womStamp) {
39.1806 + fieldMask |= WEEK_OF_MONTH_MASK;
39.1807 + } else {
39.1808 + assert (bestStamp == dowimStamp);
39.1809 + if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
39.1810 + fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
39.1811 + }
39.1812 + }
39.1813 + }
39.1814 + }
39.1815 + } else {
39.1816 + assert (bestStamp == doyStamp || bestStamp == woyStamp ||
39.1817 + bestStamp == UNSET);
39.1818 + if (bestStamp == doyStamp) {
39.1819 + fieldMask |= DAY_OF_YEAR_MASK;
39.1820 + } else {
39.1821 + assert (bestStamp == woyStamp);
39.1822 + if (dowStamp != UNSET) {
39.1823 + fieldMask |= DAY_OF_WEEK_MASK;
39.1824 + }
39.1825 + fieldMask |= WEEK_OF_YEAR_MASK;
39.1826 + }
39.1827 + }
39.1828 +
39.1829 + // Find the best set of fields specifying the time of day. There
39.1830 + // are only two possibilities here; the HOUR_OF_DAY or the
39.1831 + // AM_PM and the HOUR.
39.1832 + int hourOfDayStamp = stamp[HOUR_OF_DAY];
39.1833 + int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
39.1834 + bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
39.1835 +
39.1836 + // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
39.1837 + if (bestStamp == UNSET) {
39.1838 + bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
39.1839 + }
39.1840 +
39.1841 + // Hours
39.1842 + if (bestStamp != UNSET) {
39.1843 + if (bestStamp == hourOfDayStamp) {
39.1844 + fieldMask |= HOUR_OF_DAY_MASK;
39.1845 + } else {
39.1846 + fieldMask |= HOUR_MASK;
39.1847 + if (stamp[AM_PM] != UNSET) {
39.1848 + fieldMask |= AM_PM_MASK;
39.1849 + }
39.1850 + }
39.1851 + }
39.1852 + if (stamp[MINUTE] != UNSET) {
39.1853 + fieldMask |= MINUTE_MASK;
39.1854 + }
39.1855 + if (stamp[SECOND] != UNSET) {
39.1856 + fieldMask |= SECOND_MASK;
39.1857 + }
39.1858 + if (stamp[MILLISECOND] != UNSET) {
39.1859 + fieldMask |= MILLISECOND_MASK;
39.1860 + }
39.1861 + if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
39.1862 + fieldMask |= ZONE_OFFSET_MASK;
39.1863 + }
39.1864 + if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
39.1865 + fieldMask |= DST_OFFSET_MASK;
39.1866 + }
39.1867 +
39.1868 + return fieldMask;
39.1869 + }
39.1870 +
39.1871 + /**
39.1872 + * Returns the pseudo-time-stamp for two fields, given their
39.1873 + * individual pseudo-time-stamps. If either of the fields
39.1874 + * is unset, then the aggregate is unset. Otherwise, the
39.1875 + * aggregate is the later of the two stamps.
39.1876 + */
39.1877 + private static final int aggregateStamp(int stamp_a, int stamp_b) {
39.1878 + if (stamp_a == UNSET || stamp_b == UNSET) {
39.1879 + return UNSET;
39.1880 + }
39.1881 + return (stamp_a > stamp_b) ? stamp_a : stamp_b;
39.1882 + }
39.1883 +
39.1884 + /**
39.1885 + * Compares this <code>Calendar</code> to the specified
39.1886 + * <code>Object</code>. The result is <code>true</code> if and only if
39.1887 + * the argument is a <code>Calendar</code> object of the same calendar
39.1888 + * system that represents the same time value (millisecond offset from the
39.1889 + * <a href="#Epoch">Epoch</a>) under the same
39.1890 + * <code>Calendar</code> parameters as this object.
39.1891 + *
39.1892 + * <p>The <code>Calendar</code> parameters are the values represented
39.1893 + * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
39.1894 + * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
39.1895 + * methods. If there is any difference in those parameters
39.1896 + * between the two <code>Calendar</code>s, this method returns
39.1897 + * <code>false</code>.
39.1898 + *
39.1899 + * <p>Use the {@link #compareTo(Calendar) compareTo} method to
39.1900 + * compare only the time values.
39.1901 + *
39.1902 + * @param obj the object to compare with.
39.1903 + * @return <code>true</code> if this object is equal to <code>obj</code>;
39.1904 + * <code>false</code> otherwise.
39.1905 + */
39.1906 + public boolean equals(Object obj) {
39.1907 + if (this == obj)
39.1908 + return true;
39.1909 + try {
39.1910 + Calendar that = (Calendar)obj;
39.1911 + return compareTo(getMillisOf(that)) == 0 &&
39.1912 + lenient == that.lenient &&
39.1913 + firstDayOfWeek == that.firstDayOfWeek &&
39.1914 + minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
39.1915 + zone.equals(that.zone);
39.1916 + } catch (Exception e) {
39.1917 + // Note: GregorianCalendar.computeTime throws
39.1918 + // IllegalArgumentException if the ERA value is invalid
39.1919 + // even it's in lenient mode.
39.1920 + }
39.1921 + return false;
39.1922 + }
39.1923 +
39.1924 + /**
39.1925 + * Returns a hash code for this calendar.
39.1926 + *
39.1927 + * @return a hash code value for this object.
39.1928 + * @since 1.2
39.1929 + */
39.1930 + public int hashCode() {
39.1931 + // 'otheritems' represents the hash code for the previous versions.
39.1932 + int otheritems = (lenient ? 1 : 0)
39.1933 + | (firstDayOfWeek << 1)
39.1934 + | (minimalDaysInFirstWeek << 4)
39.1935 + | (zone.hashCode() << 7);
39.1936 + long t = getMillisOf(this);
39.1937 + return (int) t ^ (int)(t >> 32) ^ otheritems;
39.1938 + }
39.1939 +
39.1940 + /**
39.1941 + * Returns whether this <code>Calendar</code> represents a time
39.1942 + * before the time represented by the specified
39.1943 + * <code>Object</code>. This method is equivalent to:
39.1944 + * <pre><blockquote>
39.1945 + * compareTo(when) < 0
39.1946 + * </blockquote></pre>
39.1947 + * if and only if <code>when</code> is a <code>Calendar</code>
39.1948 + * instance. Otherwise, the method returns <code>false</code>.
39.1949 + *
39.1950 + * @param when the <code>Object</code> to be compared
39.1951 + * @return <code>true</code> if the time of this
39.1952 + * <code>Calendar</code> is before the time represented by
39.1953 + * <code>when</code>; <code>false</code> otherwise.
39.1954 + * @see #compareTo(Calendar)
39.1955 + */
39.1956 + public boolean before(Object when) {
39.1957 + return when instanceof Calendar
39.1958 + && compareTo((Calendar)when) < 0;
39.1959 + }
39.1960 +
39.1961 + /**
39.1962 + * Returns whether this <code>Calendar</code> represents a time
39.1963 + * after the time represented by the specified
39.1964 + * <code>Object</code>. This method is equivalent to:
39.1965 + * <pre><blockquote>
39.1966 + * compareTo(when) > 0
39.1967 + * </blockquote></pre>
39.1968 + * if and only if <code>when</code> is a <code>Calendar</code>
39.1969 + * instance. Otherwise, the method returns <code>false</code>.
39.1970 + *
39.1971 + * @param when the <code>Object</code> to be compared
39.1972 + * @return <code>true</code> if the time of this <code>Calendar</code> is
39.1973 + * after the time represented by <code>when</code>; <code>false</code>
39.1974 + * otherwise.
39.1975 + * @see #compareTo(Calendar)
39.1976 + */
39.1977 + public boolean after(Object when) {
39.1978 + return when instanceof Calendar
39.1979 + && compareTo((Calendar)when) > 0;
39.1980 + }
39.1981 +
39.1982 + /**
39.1983 + * Compares the time values (millisecond offsets from the <a
39.1984 + * href="#Epoch">Epoch</a>) represented by two
39.1985 + * <code>Calendar</code> objects.
39.1986 + *
39.1987 + * @param anotherCalendar the <code>Calendar</code> to be compared.
39.1988 + * @return the value <code>0</code> if the time represented by the argument
39.1989 + * is equal to the time represented by this <code>Calendar</code>; a value
39.1990 + * less than <code>0</code> if the time of this <code>Calendar</code> is
39.1991 + * before the time represented by the argument; and a value greater than
39.1992 + * <code>0</code> if the time of this <code>Calendar</code> is after the
39.1993 + * time represented by the argument.
39.1994 + * @exception NullPointerException if the specified <code>Calendar</code> is
39.1995 + * <code>null</code>.
39.1996 + * @exception IllegalArgumentException if the time value of the
39.1997 + * specified <code>Calendar</code> object can't be obtained due to
39.1998 + * any invalid calendar values.
39.1999 + * @since 1.5
39.2000 + */
39.2001 + public int compareTo(Calendar anotherCalendar) {
39.2002 + return compareTo(getMillisOf(anotherCalendar));
39.2003 + }
39.2004 +
39.2005 + /**
39.2006 + * Adds or subtracts the specified amount of time to the given calendar field,
39.2007 + * based on the calendar's rules. For example, to subtract 5 days from
39.2008 + * the current time of the calendar, you can achieve it by calling:
39.2009 + * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
39.2010 + *
39.2011 + * @param field the calendar field.
39.2012 + * @param amount the amount of date or time to be added to the field.
39.2013 + * @see #roll(int,int)
39.2014 + * @see #set(int,int)
39.2015 + */
39.2016 + abstract public void add(int field, int amount);
39.2017 +
39.2018 + /**
39.2019 + * Adds or subtracts (up/down) a single unit of time on the given time
39.2020 + * field without changing larger fields. For example, to roll the current
39.2021 + * date up by one day, you can achieve it by calling:
39.2022 + * <p>roll(Calendar.DATE, true).
39.2023 + * When rolling on the year or Calendar.YEAR field, it will roll the year
39.2024 + * value in the range between 1 and the value returned by calling
39.2025 + * <code>getMaximum(Calendar.YEAR)</code>.
39.2026 + * When rolling on the month or Calendar.MONTH field, other fields like
39.2027 + * date might conflict and, need to be changed. For instance,
39.2028 + * rolling the month on the date 01/31/96 will result in 02/29/96.
39.2029 + * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
39.2030 + * roll the hour value in the range between 0 and 23, which is zero-based.
39.2031 + *
39.2032 + * @param field the time field.
39.2033 + * @param up indicates if the value of the specified time field is to be
39.2034 + * rolled up or rolled down. Use true if rolling up, false otherwise.
39.2035 + * @see Calendar#add(int,int)
39.2036 + * @see Calendar#set(int,int)
39.2037 + */
39.2038 + abstract public void roll(int field, boolean up);
39.2039 +
39.2040 + /**
39.2041 + * Adds the specified (signed) amount to the specified calendar field
39.2042 + * without changing larger fields. A negative amount means to roll
39.2043 + * down.
39.2044 + *
39.2045 + * <p>NOTE: This default implementation on <code>Calendar</code> just repeatedly calls the
39.2046 + * version of {@link #roll(int,boolean) roll()} that rolls by one unit. This may not
39.2047 + * always do the right thing. For example, if the <code>DAY_OF_MONTH</code> field is 31,
39.2048 + * rolling through February will leave it set to 28. The <code>GregorianCalendar</code>
39.2049 + * version of this function takes care of this problem. Other subclasses
39.2050 + * should also provide overrides of this function that do the right thing.
39.2051 + *
39.2052 + * @param field the calendar field.
39.2053 + * @param amount the signed amount to add to the calendar <code>field</code>.
39.2054 + * @since 1.2
39.2055 + * @see #roll(int,boolean)
39.2056 + * @see #add(int,int)
39.2057 + * @see #set(int,int)
39.2058 + */
39.2059 + public void roll(int field, int amount)
39.2060 + {
39.2061 + while (amount > 0) {
39.2062 + roll(field, true);
39.2063 + amount--;
39.2064 + }
39.2065 + while (amount < 0) {
39.2066 + roll(field, false);
39.2067 + amount++;
39.2068 + }
39.2069 + }
39.2070 +
39.2071 + /**
39.2072 + * Sets the time zone with the given time zone value.
39.2073 + *
39.2074 + * @param value the given time zone.
39.2075 + */
39.2076 + public void setTimeZone(TimeZone value)
39.2077 + {
39.2078 + zone = value;
39.2079 + sharedZone = false;
39.2080 + /* Recompute the fields from the time using the new zone. This also
39.2081 + * works if isTimeSet is false (after a call to set()). In that case
39.2082 + * the time will be computed from the fields using the new zone, then
39.2083 + * the fields will get recomputed from that. Consider the sequence of
39.2084 + * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
39.2085 + * Is cal set to 1 o'clock EST or 1 o'clock PST? Answer: PST. More
39.2086 + * generally, a call to setTimeZone() affects calls to set() BEFORE AND
39.2087 + * AFTER it up to the next call to complete().
39.2088 + */
39.2089 + areAllFieldsSet = areFieldsSet = false;
39.2090 + }
39.2091 +
39.2092 + /**
39.2093 + * Gets the time zone.
39.2094 + *
39.2095 + * @return the time zone object associated with this calendar.
39.2096 + */
39.2097 + public TimeZone getTimeZone()
39.2098 + {
39.2099 + // If the TimeZone object is shared by other Calendar instances, then
39.2100 + // create a clone.
39.2101 + if (sharedZone) {
39.2102 + zone = (TimeZone) zone.clone();
39.2103 + sharedZone = false;
39.2104 + }
39.2105 + return zone;
39.2106 + }
39.2107 +
39.2108 + /**
39.2109 + * Returns the time zone (without cloning).
39.2110 + */
39.2111 + TimeZone getZone() {
39.2112 + return zone;
39.2113 + }
39.2114 +
39.2115 + /**
39.2116 + * Sets the sharedZone flag to <code>shared</code>.
39.2117 + */
39.2118 + void setZoneShared(boolean shared) {
39.2119 + sharedZone = shared;
39.2120 + }
39.2121 +
39.2122 + /**
39.2123 + * Specifies whether or not date/time interpretation is to be lenient. With
39.2124 + * lenient interpretation, a date such as "February 942, 1996" will be
39.2125 + * treated as being equivalent to the 941st day after February 1, 1996.
39.2126 + * With strict (non-lenient) interpretation, such dates will cause an exception to be
39.2127 + * thrown. The default is lenient.
39.2128 + *
39.2129 + * @param lenient <code>true</code> if the lenient mode is to be turned
39.2130 + * on; <code>false</code> if it is to be turned off.
39.2131 + * @see #isLenient()
39.2132 + * @see java.text.DateFormat#setLenient
39.2133 + */
39.2134 + public void setLenient(boolean lenient)
39.2135 + {
39.2136 + this.lenient = lenient;
39.2137 + }
39.2138 +
39.2139 + /**
39.2140 + * Tells whether date/time interpretation is to be lenient.
39.2141 + *
39.2142 + * @return <code>true</code> if the interpretation mode of this calendar is lenient;
39.2143 + * <code>false</code> otherwise.
39.2144 + * @see #setLenient(boolean)
39.2145 + */
39.2146 + public boolean isLenient()
39.2147 + {
39.2148 + return lenient;
39.2149 + }
39.2150 +
39.2151 + /**
39.2152 + * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
39.2153 + * <code>MONDAY</code> in France.
39.2154 + *
39.2155 + * @param value the given first day of the week.
39.2156 + * @see #getFirstDayOfWeek()
39.2157 + * @see #getMinimalDaysInFirstWeek()
39.2158 + */
39.2159 + public void setFirstDayOfWeek(int value)
39.2160 + {
39.2161 + if (firstDayOfWeek == value) {
39.2162 + return;
39.2163 + }
39.2164 + firstDayOfWeek = value;
39.2165 + invalidateWeekFields();
39.2166 + }
39.2167 +
39.2168 + /**
39.2169 + * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
39.2170 + * <code>MONDAY</code> in France.
39.2171 + *
39.2172 + * @return the first day of the week.
39.2173 + * @see #setFirstDayOfWeek(int)
39.2174 + * @see #getMinimalDaysInFirstWeek()
39.2175 + */
39.2176 + public int getFirstDayOfWeek()
39.2177 + {
39.2178 + return firstDayOfWeek;
39.2179 + }
39.2180 +
39.2181 + /**
39.2182 + * Sets what the minimal days required in the first week of the year are;
39.2183 + * For example, if the first week is defined as one that contains the first
39.2184 + * day of the first month of a year, call this method with value 1. If it
39.2185 + * must be a full week, use value 7.
39.2186 + *
39.2187 + * @param value the given minimal days required in the first week
39.2188 + * of the year.
39.2189 + * @see #getMinimalDaysInFirstWeek()
39.2190 + */
39.2191 + public void setMinimalDaysInFirstWeek(int value)
39.2192 + {
39.2193 + if (minimalDaysInFirstWeek == value) {
39.2194 + return;
39.2195 + }
39.2196 + minimalDaysInFirstWeek = value;
39.2197 + invalidateWeekFields();
39.2198 + }
39.2199 +
39.2200 + /**
39.2201 + * Gets what the minimal days required in the first week of the year are;
39.2202 + * e.g., if the first week is defined as one that contains the first day
39.2203 + * of the first month of a year, this method returns 1. If
39.2204 + * the minimal days required must be a full week, this method
39.2205 + * returns 7.
39.2206 + *
39.2207 + * @return the minimal days required in the first week of the year.
39.2208 + * @see #setMinimalDaysInFirstWeek(int)
39.2209 + */
39.2210 + public int getMinimalDaysInFirstWeek()
39.2211 + {
39.2212 + return minimalDaysInFirstWeek;
39.2213 + }
39.2214 +
39.2215 + /**
39.2216 + * Returns whether this {@code Calendar} supports week dates.
39.2217 + *
39.2218 + * <p>The default implementation of this method returns {@code false}.
39.2219 + *
39.2220 + * @return {@code true} if this {@code Calendar} supports week dates;
39.2221 + * {@code false} otherwise.
39.2222 + * @see #getWeekYear()
39.2223 + * @see #setWeekDate(int,int,int)
39.2224 + * @see #getWeeksInWeekYear()
39.2225 + * @since 1.7
39.2226 + */
39.2227 + public boolean isWeekDateSupported() {
39.2228 + return false;
39.2229 + }
39.2230 +
39.2231 + /**
39.2232 + * Returns the week year represented by this {@code Calendar}. The
39.2233 + * week year is in sync with the week cycle. The {@linkplain
39.2234 + * #getFirstDayOfWeek() first day of the first week} is the first
39.2235 + * day of the week year.
39.2236 + *
39.2237 + * <p>The default implementation of this method throws an
39.2238 + * {@link UnsupportedOperationException}.
39.2239 + *
39.2240 + * @return the week year of this {@code Calendar}
39.2241 + * @exception UnsupportedOperationException
39.2242 + * if any week year numbering isn't supported
39.2243 + * in this {@code Calendar}.
39.2244 + * @see #isWeekDateSupported()
39.2245 + * @see #getFirstDayOfWeek()
39.2246 + * @see #getMinimalDaysInFirstWeek()
39.2247 + * @since 1.7
39.2248 + */
39.2249 + public int getWeekYear() {
39.2250 + throw new UnsupportedOperationException();
39.2251 + }
39.2252 +
39.2253 + /**
39.2254 + * Sets the date of this {@code Calendar} with the the given date
39.2255 + * specifiers - week year, week of year, and day of week.
39.2256 + *
39.2257 + * <p>Unlike the {@code set} method, all of the calendar fields
39.2258 + * and {@code time} values are calculated upon return.
39.2259 + *
39.2260 + * <p>If {@code weekOfYear} is out of the valid week-of-year range
39.2261 + * in {@code weekYear}, the {@code weekYear} and {@code
39.2262 + * weekOfYear} values are adjusted in lenient mode, or an {@code
39.2263 + * IllegalArgumentException} is thrown in non-lenient mode.
39.2264 + *
39.2265 + * <p>The default implementation of this method throws an
39.2266 + * {@code UnsupportedOperationException}.
39.2267 + *
39.2268 + * @param weekYear the week year
39.2269 + * @param weekOfYear the week number based on {@code weekYear}
39.2270 + * @param dayOfWeek the day of week value: one of the constants
39.2271 + * for the {@link #DAY_OF_WEEK} field: {@link
39.2272 + * #SUNDAY}, ..., {@link #SATURDAY}.
39.2273 + * @exception IllegalArgumentException
39.2274 + * if any of the given date specifiers is invalid
39.2275 + * or any of the calendar fields are inconsistent
39.2276 + * with the given date specifiers in non-lenient mode
39.2277 + * @exception UnsupportedOperationException
39.2278 + * if any week year numbering isn't supported in this
39.2279 + * {@code Calendar}.
39.2280 + * @see #isWeekDateSupported()
39.2281 + * @see #getFirstDayOfWeek()
39.2282 + * @see #getMinimalDaysInFirstWeek()
39.2283 + * @since 1.7
39.2284 + */
39.2285 + public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
39.2286 + throw new UnsupportedOperationException();
39.2287 + }
39.2288 +
39.2289 + /**
39.2290 + * Returns the number of weeks in the week year represented by this
39.2291 + * {@code Calendar}.
39.2292 + *
39.2293 + * <p>The default implementation of this method throws an
39.2294 + * {@code UnsupportedOperationException}.
39.2295 + *
39.2296 + * @return the number of weeks in the week year.
39.2297 + * @exception UnsupportedOperationException
39.2298 + * if any week year numbering isn't supported in this
39.2299 + * {@code Calendar}.
39.2300 + * @see #WEEK_OF_YEAR
39.2301 + * @see #isWeekDateSupported()
39.2302 + * @see #getWeekYear()
39.2303 + * @see #getActualMaximum(int)
39.2304 + * @since 1.7
39.2305 + */
39.2306 + public int getWeeksInWeekYear() {
39.2307 + throw new UnsupportedOperationException();
39.2308 + }
39.2309 +
39.2310 + /**
39.2311 + * Returns the minimum value for the given calendar field of this
39.2312 + * <code>Calendar</code> instance. The minimum value is defined as
39.2313 + * the smallest value returned by the {@link #get(int) get} method
39.2314 + * for any possible time value. The minimum value depends on
39.2315 + * calendar system specific parameters of the instance.
39.2316 + *
39.2317 + * @param field the calendar field.
39.2318 + * @return the minimum value for the given calendar field.
39.2319 + * @see #getMaximum(int)
39.2320 + * @see #getGreatestMinimum(int)
39.2321 + * @see #getLeastMaximum(int)
39.2322 + * @see #getActualMinimum(int)
39.2323 + * @see #getActualMaximum(int)
39.2324 + */
39.2325 + abstract public int getMinimum(int field);
39.2326 +
39.2327 + /**
39.2328 + * Returns the maximum value for the given calendar field of this
39.2329 + * <code>Calendar</code> instance. The maximum value is defined as
39.2330 + * the largest value returned by the {@link #get(int) get} method
39.2331 + * for any possible time value. The maximum value depends on
39.2332 + * calendar system specific parameters of the instance.
39.2333 + *
39.2334 + * @param field the calendar field.
39.2335 + * @return the maximum value for the given calendar field.
39.2336 + * @see #getMinimum(int)
39.2337 + * @see #getGreatestMinimum(int)
39.2338 + * @see #getLeastMaximum(int)
39.2339 + * @see #getActualMinimum(int)
39.2340 + * @see #getActualMaximum(int)
39.2341 + */
39.2342 + abstract public int getMaximum(int field);
39.2343 +
39.2344 + /**
39.2345 + * Returns the highest minimum value for the given calendar field
39.2346 + * of this <code>Calendar</code> instance. The highest minimum
39.2347 + * value is defined as the largest value returned by {@link
39.2348 + * #getActualMinimum(int)} for any possible time value. The
39.2349 + * greatest minimum value depends on calendar system specific
39.2350 + * parameters of the instance.
39.2351 + *
39.2352 + * @param field the calendar field.
39.2353 + * @return the highest minimum value for the given calendar field.
39.2354 + * @see #getMinimum(int)
39.2355 + * @see #getMaximum(int)
39.2356 + * @see #getLeastMaximum(int)
39.2357 + * @see #getActualMinimum(int)
39.2358 + * @see #getActualMaximum(int)
39.2359 + */
39.2360 + abstract public int getGreatestMinimum(int field);
39.2361 +
39.2362 + /**
39.2363 + * Returns the lowest maximum value for the given calendar field
39.2364 + * of this <code>Calendar</code> instance. The lowest maximum
39.2365 + * value is defined as the smallest value returned by {@link
39.2366 + * #getActualMaximum(int)} for any possible time value. The least
39.2367 + * maximum value depends on calendar system specific parameters of
39.2368 + * the instance. For example, a <code>Calendar</code> for the
39.2369 + * Gregorian calendar system returns 28 for the
39.2370 + * <code>DAY_OF_MONTH</code> field, because the 28th is the last
39.2371 + * day of the shortest month of this calendar, February in a
39.2372 + * common year.
39.2373 + *
39.2374 + * @param field the calendar field.
39.2375 + * @return the lowest maximum value for the given calendar field.
39.2376 + * @see #getMinimum(int)
39.2377 + * @see #getMaximum(int)
39.2378 + * @see #getGreatestMinimum(int)
39.2379 + * @see #getActualMinimum(int)
39.2380 + * @see #getActualMaximum(int)
39.2381 + */
39.2382 + abstract public int getLeastMaximum(int field);
39.2383 +
39.2384 + /**
39.2385 + * Returns the minimum value that the specified calendar field
39.2386 + * could have, given the time value of this <code>Calendar</code>.
39.2387 + *
39.2388 + * <p>The default implementation of this method uses an iterative
39.2389 + * algorithm to determine the actual minimum value for the
39.2390 + * calendar field. Subclasses should, if possible, override this
39.2391 + * with a more efficient implementation - in many cases, they can
39.2392 + * simply return <code>getMinimum()</code>.
39.2393 + *
39.2394 + * @param field the calendar field
39.2395 + * @return the minimum of the given calendar field for the time
39.2396 + * value of this <code>Calendar</code>
39.2397 + * @see #getMinimum(int)
39.2398 + * @see #getMaximum(int)
39.2399 + * @see #getGreatestMinimum(int)
39.2400 + * @see #getLeastMaximum(int)
39.2401 + * @see #getActualMaximum(int)
39.2402 + * @since 1.2
39.2403 + */
39.2404 + public int getActualMinimum(int field) {
39.2405 + int fieldValue = getGreatestMinimum(field);
39.2406 + int endValue = getMinimum(field);
39.2407 +
39.2408 + // if we know that the minimum value is always the same, just return it
39.2409 + if (fieldValue == endValue) {
39.2410 + return fieldValue;
39.2411 + }
39.2412 +
39.2413 + // clone the calendar so we don't mess with the real one, and set it to
39.2414 + // accept anything for the field values
39.2415 + Calendar work = (Calendar)this.clone();
39.2416 + work.setLenient(true);
39.2417 +
39.2418 + // now try each value from getLeastMaximum() to getMaximum() one by one until
39.2419 + // we get a value that normalizes to another value. The last value that
39.2420 + // normalizes to itself is the actual minimum for the current date
39.2421 + int result = fieldValue;
39.2422 +
39.2423 + do {
39.2424 + work.set(field, fieldValue);
39.2425 + if (work.get(field) != fieldValue) {
39.2426 + break;
39.2427 + } else {
39.2428 + result = fieldValue;
39.2429 + fieldValue--;
39.2430 + }
39.2431 + } while (fieldValue >= endValue);
39.2432 +
39.2433 + return result;
39.2434 + }
39.2435 +
39.2436 + /**
39.2437 + * Returns the maximum value that the specified calendar field
39.2438 + * could have, given the time value of this
39.2439 + * <code>Calendar</code>. For example, the actual maximum value of
39.2440 + * the <code>MONTH</code> field is 12 in some years, and 13 in
39.2441 + * other years in the Hebrew calendar system.
39.2442 + *
39.2443 + * <p>The default implementation of this method uses an iterative
39.2444 + * algorithm to determine the actual maximum value for the
39.2445 + * calendar field. Subclasses should, if possible, override this
39.2446 + * with a more efficient implementation.
39.2447 + *
39.2448 + * @param field the calendar field
39.2449 + * @return the maximum of the given calendar field for the time
39.2450 + * value of this <code>Calendar</code>
39.2451 + * @see #getMinimum(int)
39.2452 + * @see #getMaximum(int)
39.2453 + * @see #getGreatestMinimum(int)
39.2454 + * @see #getLeastMaximum(int)
39.2455 + * @see #getActualMinimum(int)
39.2456 + * @since 1.2
39.2457 + */
39.2458 + public int getActualMaximum(int field) {
39.2459 + int fieldValue = getLeastMaximum(field);
39.2460 + int endValue = getMaximum(field);
39.2461 +
39.2462 + // if we know that the maximum value is always the same, just return it.
39.2463 + if (fieldValue == endValue) {
39.2464 + return fieldValue;
39.2465 + }
39.2466 +
39.2467 + // clone the calendar so we don't mess with the real one, and set it to
39.2468 + // accept anything for the field values.
39.2469 + Calendar work = (Calendar)this.clone();
39.2470 + work.setLenient(true);
39.2471 +
39.2472 + // if we're counting weeks, set the day of the week to Sunday. We know the
39.2473 + // last week of a month or year will contain the first day of the week.
39.2474 + if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH)
39.2475 + work.set(DAY_OF_WEEK, firstDayOfWeek);
39.2476 +
39.2477 + // now try each value from getLeastMaximum() to getMaximum() one by one until
39.2478 + // we get a value that normalizes to another value. The last value that
39.2479 + // normalizes to itself is the actual maximum for the current date
39.2480 + int result = fieldValue;
39.2481 +
39.2482 + do {
39.2483 + work.set(field, fieldValue);
39.2484 + if (work.get(field) != fieldValue) {
39.2485 + break;
39.2486 + } else {
39.2487 + result = fieldValue;
39.2488 + fieldValue++;
39.2489 + }
39.2490 + } while (fieldValue <= endValue);
39.2491 +
39.2492 + return result;
39.2493 + }
39.2494 +
39.2495 + /**
39.2496 + * Creates and returns a copy of this object.
39.2497 + *
39.2498 + * @return a copy of this object.
39.2499 + */
39.2500 + public Object clone()
39.2501 + {
39.2502 + try {
39.2503 + Calendar other = (Calendar) super.clone();
39.2504 +
39.2505 + other.fields = new int[FIELD_COUNT];
39.2506 + other.isSet = new boolean[FIELD_COUNT];
39.2507 + other.stamp = new int[FIELD_COUNT];
39.2508 + for (int i = 0; i < FIELD_COUNT; i++) {
39.2509 + other.fields[i] = fields[i];
39.2510 + other.stamp[i] = stamp[i];
39.2511 + other.isSet[i] = isSet[i];
39.2512 + }
39.2513 + other.zone = (TimeZone) zone.clone();
39.2514 + return other;
39.2515 + }
39.2516 + catch (CloneNotSupportedException e) {
39.2517 + // this shouldn't happen, since we are Cloneable
39.2518 + throw new InternalError();
39.2519 + }
39.2520 + }
39.2521 +
39.2522 + private static final String[] FIELD_NAME = {
39.2523 + "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
39.2524 + "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
39.2525 + "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
39.2526 + "DST_OFFSET"
39.2527 + };
39.2528 +
39.2529 + /**
39.2530 + * Returns the name of the specified calendar field.
39.2531 + *
39.2532 + * @param field the calendar field
39.2533 + * @return the calendar field name
39.2534 + * @exception IndexOutOfBoundsException if <code>field</code> is negative,
39.2535 + * equal to or greater then <code>FIELD_COUNT</code>.
39.2536 + */
39.2537 + static final String getFieldName(int field) {
39.2538 + return FIELD_NAME[field];
39.2539 + }
39.2540 +
39.2541 + /**
39.2542 + * Return a string representation of this calendar. This method
39.2543 + * is intended to be used only for debugging purposes, and the
39.2544 + * format of the returned string may vary between implementations.
39.2545 + * The returned string may be empty but may not be <code>null</code>.
39.2546 + *
39.2547 + * @return a string representation of this calendar.
39.2548 + */
39.2549 + public String toString() {
39.2550 + // NOTE: BuddhistCalendar.toString() interprets the string
39.2551 + // produced by this method so that the Gregorian year number
39.2552 + // is substituted by its B.E. year value. It relies on
39.2553 + // "...,YEAR=<year>,..." or "...,YEAR=?,...".
39.2554 + StringBuilder buffer = new StringBuilder(800);
39.2555 + buffer.append(getClass().getName()).append('[');
39.2556 + appendValue(buffer, "time", isTimeSet, time);
39.2557 + buffer.append(",areFieldsSet=").append(areFieldsSet);
39.2558 + buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
39.2559 + buffer.append(",lenient=").append(lenient);
39.2560 + buffer.append(",zone=").append(zone);
39.2561 + appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
39.2562 + appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
39.2563 + for (int i = 0; i < FIELD_COUNT; ++i) {
39.2564 + buffer.append(',');
39.2565 + appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
39.2566 + }
39.2567 + buffer.append(']');
39.2568 + return buffer.toString();
39.2569 + }
39.2570 +
39.2571 + // =======================privates===============================
39.2572 +
39.2573 + private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) {
39.2574 + sb.append(item).append('=');
39.2575 + if (valid) {
39.2576 + sb.append(value);
39.2577 + } else {
39.2578 + sb.append('?');
39.2579 + }
39.2580 + }
39.2581 +
39.2582 + /**
39.2583 + * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
39.2584 + * They are used to figure out the week count for a specific date for
39.2585 + * a given locale. These must be set when a Calendar is constructed.
39.2586 + * @param desiredLocale the given locale.
39.2587 + */
39.2588 + private void setWeekCountData(Locale desiredLocale)
39.2589 + {
39.2590 + /* try to get the Locale data from the cache */
39.2591 + int[] data = cachedLocaleData.get(desiredLocale);
39.2592 + if (data == null) { /* cache miss */
39.2593 + ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale);
39.2594 + data = new int[2];
39.2595 + data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
39.2596 + data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
39.2597 + cachedLocaleData.putIfAbsent(desiredLocale, data);
39.2598 + }
39.2599 + firstDayOfWeek = data[0];
39.2600 + minimalDaysInFirstWeek = data[1];
39.2601 + }
39.2602 +
39.2603 + /**
39.2604 + * Recomputes the time and updates the status fields isTimeSet
39.2605 + * and areFieldsSet. Callers should check isTimeSet and only
39.2606 + * call this method if isTimeSet is false.
39.2607 + */
39.2608 + private void updateTime() {
39.2609 + computeTime();
39.2610 + // The areFieldsSet and areAllFieldsSet values are no longer
39.2611 + // controlled here (as of 1.5).
39.2612 + isTimeSet = true;
39.2613 + }
39.2614 +
39.2615 + private int compareTo(long t) {
39.2616 + long thisTime = getMillisOf(this);
39.2617 + return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
39.2618 + }
39.2619 +
39.2620 + private static final long getMillisOf(Calendar calendar) {
39.2621 + if (calendar.isTimeSet) {
39.2622 + return calendar.time;
39.2623 + }
39.2624 + Calendar cal = (Calendar) calendar.clone();
39.2625 + cal.setLenient(true);
39.2626 + return cal.getTimeInMillis();
39.2627 + }
39.2628 +
39.2629 + /**
39.2630 + * Adjusts the stamp[] values before nextStamp overflow. nextStamp
39.2631 + * is set to the next stamp value upon the return.
39.2632 + */
39.2633 + private final void adjustStamp() {
39.2634 + int max = MINIMUM_USER_STAMP;
39.2635 + int newStamp = MINIMUM_USER_STAMP;
39.2636 +
39.2637 + for (;;) {
39.2638 + int min = Integer.MAX_VALUE;
39.2639 + for (int i = 0; i < stamp.length; i++) {
39.2640 + int v = stamp[i];
39.2641 + if (v >= newStamp && min > v) {
39.2642 + min = v;
39.2643 + }
39.2644 + if (max < v) {
39.2645 + max = v;
39.2646 + }
39.2647 + }
39.2648 + if (max != min && min == Integer.MAX_VALUE) {
39.2649 + break;
39.2650 + }
39.2651 + for (int i = 0; i < stamp.length; i++) {
39.2652 + if (stamp[i] == min) {
39.2653 + stamp[i] = newStamp;
39.2654 + }
39.2655 + }
39.2656 + newStamp++;
39.2657 + if (min == max) {
39.2658 + break;
39.2659 + }
39.2660 + }
39.2661 + nextStamp = newStamp;
39.2662 + }
39.2663 +
39.2664 + /**
39.2665 + * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
39.2666 + * new parameter value if they have been calculated internally.
39.2667 + */
39.2668 + private void invalidateWeekFields()
39.2669 + {
39.2670 + if (stamp[WEEK_OF_MONTH] != COMPUTED &&
39.2671 + stamp[WEEK_OF_YEAR] != COMPUTED) {
39.2672 + return;
39.2673 + }
39.2674 +
39.2675 + // We have to check the new values of these fields after changing
39.2676 + // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
39.2677 + // have been changed, then set the new values. (4822110)
39.2678 + Calendar cal = (Calendar) clone();
39.2679 + cal.setLenient(true);
39.2680 + cal.clear(WEEK_OF_MONTH);
39.2681 + cal.clear(WEEK_OF_YEAR);
39.2682 +
39.2683 + if (stamp[WEEK_OF_MONTH] == COMPUTED) {
39.2684 + int weekOfMonth = cal.get(WEEK_OF_MONTH);
39.2685 + if (fields[WEEK_OF_MONTH] != weekOfMonth) {
39.2686 + fields[WEEK_OF_MONTH] = weekOfMonth;
39.2687 + }
39.2688 + }
39.2689 +
39.2690 + if (stamp[WEEK_OF_YEAR] == COMPUTED) {
39.2691 + int weekOfYear = cal.get(WEEK_OF_YEAR);
39.2692 + if (fields[WEEK_OF_YEAR] != weekOfYear) {
39.2693 + fields[WEEK_OF_YEAR] = weekOfYear;
39.2694 + }
39.2695 + }
39.2696 + }
39.2697 +
39.2698 + /**
39.2699 + * Save the state of this object to a stream (i.e., serialize it).
39.2700 + *
39.2701 + * Ideally, <code>Calendar</code> would only write out its state data and
39.2702 + * the current time, and not write any field data out, such as
39.2703 + * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
39.2704 + * and <code>isSet[]</code>. <code>nextStamp</code> also should not be part
39.2705 + * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
39.2706 + * shipped. To be compatible with JDK 1.1, we will always have to write out
39.2707 + * the field values and state flags. However, <code>nextStamp</code> can be
39.2708 + * removed from the serialization stream; this will probably happen in the
39.2709 + * near future.
39.2710 + */
39.2711 + private void writeObject(ObjectOutputStream stream)
39.2712 + throws IOException
39.2713 + {
39.2714 + // Try to compute the time correctly, for the future (stream
39.2715 + // version 2) in which we don't write out fields[] or isSet[].
39.2716 + if (!isTimeSet) {
39.2717 + try {
39.2718 + updateTime();
39.2719 + }
39.2720 + catch (IllegalArgumentException e) {}
39.2721 + }
39.2722 +
39.2723 + // If this Calendar has a ZoneInfo, save it and set a
39.2724 + // SimpleTimeZone equivalent (as a single DST schedule) for
39.2725 + // backward compatibility.
39.2726 + TimeZone savedZone = null;
39.2727 + if (zone instanceof ZoneInfo) {
39.2728 + SimpleTimeZone stz = ((ZoneInfo)zone).getLastRuleInstance();
39.2729 + if (stz == null) {
39.2730 + stz = new SimpleTimeZone(zone.getRawOffset(), zone.getID());
39.2731 + }
39.2732 + savedZone = zone;
39.2733 + zone = stz;
39.2734 + }
39.2735 +
39.2736 + // Write out the 1.1 FCS object.
39.2737 + stream.defaultWriteObject();
39.2738 +
39.2739 + // Write out the ZoneInfo object
39.2740 + // 4802409: we write out even if it is null, a temporary workaround
39.2741 + // the real fix for bug 4844924 in corba-iiop
39.2742 + stream.writeObject(savedZone);
39.2743 + if (savedZone != null) {
39.2744 + zone = savedZone;
39.2745 + }
39.2746 + }
39.2747 +
39.2748 + private static class CalendarAccessControlContext {
39.2749 + private static final AccessControlContext INSTANCE;
39.2750 + static {
39.2751 + RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
39.2752 + PermissionCollection perms = perm.newPermissionCollection();
39.2753 + perms.add(perm);
39.2754 + INSTANCE = new AccessControlContext(new ProtectionDomain[] {
39.2755 + new ProtectionDomain(null, perms)
39.2756 + });
39.2757 + }
39.2758 + }
39.2759 +
39.2760 + /**
39.2761 + * Reconstitutes this object from a stream (i.e., deserialize it).
39.2762 + */
39.2763 + private void readObject(ObjectInputStream stream)
39.2764 + throws IOException, ClassNotFoundException
39.2765 + {
39.2766 + final ObjectInputStream input = stream;
39.2767 + input.defaultReadObject();
39.2768 +
39.2769 + stamp = new int[FIELD_COUNT];
39.2770 +
39.2771 + // Starting with version 2 (not implemented yet), we expect that
39.2772 + // fields[], isSet[], isTimeSet, and areFieldsSet may not be
39.2773 + // streamed out anymore. We expect 'time' to be correct.
39.2774 + if (serialVersionOnStream >= 2)
39.2775 + {
39.2776 + isTimeSet = true;
39.2777 + if (fields == null) fields = new int[FIELD_COUNT];
39.2778 + if (isSet == null) isSet = new boolean[FIELD_COUNT];
39.2779 + }
39.2780 + else if (serialVersionOnStream >= 0)
39.2781 + {
39.2782 + for (int i=0; i<FIELD_COUNT; ++i)
39.2783 + stamp[i] = isSet[i] ? COMPUTED : UNSET;
39.2784 + }
39.2785 +
39.2786 + serialVersionOnStream = currentSerialVersion;
39.2787 +
39.2788 + // If there's a ZoneInfo object, use it for zone.
39.2789 + ZoneInfo zi = null;
39.2790 + try {
39.2791 + zi = AccessController.doPrivileged(
39.2792 + new PrivilegedExceptionAction<ZoneInfo>() {
39.2793 + public ZoneInfo run() throws Exception {
39.2794 + return (ZoneInfo) input.readObject();
39.2795 + }
39.2796 + },
39.2797 + CalendarAccessControlContext.INSTANCE);
39.2798 + } catch (PrivilegedActionException pae) {
39.2799 + Exception e = pae.getException();
39.2800 + if (!(e instanceof OptionalDataException)) {
39.2801 + if (e instanceof RuntimeException) {
39.2802 + throw (RuntimeException) e;
39.2803 + } else if (e instanceof IOException) {
39.2804 + throw (IOException) e;
39.2805 + } else if (e instanceof ClassNotFoundException) {
39.2806 + throw (ClassNotFoundException) e;
39.2807 + }
39.2808 + throw new RuntimeException(e);
39.2809 + }
39.2810 + }
39.2811 + if (zi != null) {
39.2812 + zone = zi;
39.2813 + }
39.2814 +
39.2815 + // If the deserialized object has a SimpleTimeZone, try to
39.2816 + // replace it with a ZoneInfo equivalent (as of 1.4) in order
39.2817 + // to be compatible with the SimpleTimeZone-based
39.2818 + // implementation as much as possible.
39.2819 + if (zone instanceof SimpleTimeZone) {
39.2820 + String id = zone.getID();
39.2821 + TimeZone tz = TimeZone.getTimeZone(id);
39.2822 + if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
39.2823 + zone = tz;
39.2824 + }
39.2825 + }
39.2826 + }
39.2827 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/rt/emul/compact/src/main/java/java/util/Currency.java Thu Oct 03 15:40:35 2013 +0200
40.3 @@ -0,0 +1,741 @@
40.4 +/*
40.5 + * Copyright (c) 2000, 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 +package java.util;
40.30 +
40.31 +import java.io.BufferedInputStream;
40.32 +import java.io.DataInputStream;
40.33 +import java.io.File;
40.34 +import java.io.FileInputStream;
40.35 +import java.io.FileReader;
40.36 +import java.io.IOException;
40.37 +import java.io.Serializable;
40.38 +import java.security.AccessController;
40.39 +import java.security.PrivilegedAction;
40.40 +import java.util.logging.Level;
40.41 +import java.util.regex.Pattern;
40.42 +import java.util.regex.Matcher;
40.43 +import java.util.spi.CurrencyNameProvider;
40.44 +import java.util.spi.LocaleServiceProvider;
40.45 +import sun.util.LocaleServiceProviderPool;
40.46 +import sun.util.logging.PlatformLogger;
40.47 +import sun.util.resources.LocaleData;
40.48 +import sun.util.resources.OpenListResourceBundle;
40.49 +
40.50 +
40.51 +/**
40.52 + * Represents a currency. Currencies are identified by their ISO 4217 currency
40.53 + * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
40.54 + * ISO web site</a> for more information, including a table of
40.55 + * currency codes.
40.56 + * <p>
40.57 + * The class is designed so that there's never more than one
40.58 + * <code>Currency</code> instance for any given currency. Therefore, there's
40.59 + * no public constructor. You obtain a <code>Currency</code> instance using
40.60 + * the <code>getInstance</code> methods.
40.61 + * <p>
40.62 + * Users can supersede the Java runtime currency data by creating a properties
40.63 + * file named <code><JAVA_HOME>/lib/currency.properties</code>. The contents
40.64 + * of the properties file are key/value pairs of the ISO 3166 country codes
40.65 + * and the ISO 4217 currency data respectively. The value part consists of
40.66 + * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
40.67 + * code, and a minor unit. Those three ISO 4217 values are separated by commas.
40.68 + * The lines which start with '#'s are considered comment lines. For example,
40.69 + * <p>
40.70 + * <code>
40.71 + * #Sample currency properties<br>
40.72 + * JP=JPZ,999,0
40.73 + * </code>
40.74 + * <p>
40.75 + * will supersede the currency data for Japan.
40.76 + *
40.77 + * @since 1.4
40.78 + */
40.79 +public final class Currency implements Serializable {
40.80 +
40.81 + private static final long serialVersionUID = -158308464356906721L;
40.82 +
40.83 + /**
40.84 + * ISO 4217 currency code for this currency.
40.85 + *
40.86 + * @serial
40.87 + */
40.88 + private final String currencyCode;
40.89 +
40.90 + /**
40.91 + * Default fraction digits for this currency.
40.92 + * Set from currency data tables.
40.93 + */
40.94 + transient private final int defaultFractionDigits;
40.95 +
40.96 + /**
40.97 + * ISO 4217 numeric code for this currency.
40.98 + * Set from currency data tables.
40.99 + */
40.100 + transient private final int numericCode;
40.101 +
40.102 +
40.103 + // class data: instance map
40.104 +
40.105 + private static HashMap<String, Currency> instances = new HashMap<String, Currency>(7);
40.106 + private static HashSet<Currency> available;
40.107 +
40.108 +
40.109 + // Class data: currency data obtained from currency.data file.
40.110 + // Purpose:
40.111 + // - determine valid country codes
40.112 + // - determine valid currency codes
40.113 + // - map country codes to currency codes
40.114 + // - obtain default fraction digits for currency codes
40.115 + //
40.116 + // sc = special case; dfd = default fraction digits
40.117 + // Simple countries are those where the country code is a prefix of the
40.118 + // currency code, and there are no known plans to change the currency.
40.119 + //
40.120 + // table formats:
40.121 + // - mainTable:
40.122 + // - maps country code to 32-bit int
40.123 + // - 26*26 entries, corresponding to [A-Z]*[A-Z]
40.124 + // - \u007F -> not valid country
40.125 + // - bits 18-31: unused
40.126 + // - bits 8-17: numeric code (0 to 1023)
40.127 + // - bit 7: 1 - special case, bits 0-4 indicate which one
40.128 + // 0 - simple country, bits 0-4 indicate final char of currency code
40.129 + // - bits 5-6: fraction digits for simple countries, 0 for special cases
40.130 + // - bits 0-4: final char for currency code for simple country, or ID of special case
40.131 + // - special case IDs:
40.132 + // - 0: country has no currency
40.133 + // - other: index into sc* arrays + 1
40.134 + // - scCutOverTimes: cut-over time in millis as returned by
40.135 + // System.currentTimeMillis for special case countries that are changing
40.136 + // currencies; Long.MAX_VALUE for countries that are not changing currencies
40.137 + // - scOldCurrencies: old currencies for special case countries
40.138 + // - scNewCurrencies: new currencies for special case countries that are
40.139 + // changing currencies; null for others
40.140 + // - scOldCurrenciesDFD: default fraction digits for old currencies
40.141 + // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
40.142 + // countries that are not changing currencies
40.143 + // - otherCurrencies: concatenation of all currency codes that are not the
40.144 + // main currency of a simple country, separated by "-"
40.145 + // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
40.146 +
40.147 + static int formatVersion;
40.148 + static int dataVersion;
40.149 + static int[] mainTable;
40.150 + static long[] scCutOverTimes;
40.151 + static String[] scOldCurrencies;
40.152 + static String[] scNewCurrencies;
40.153 + static int[] scOldCurrenciesDFD;
40.154 + static int[] scNewCurrenciesDFD;
40.155 + static int[] scOldCurrenciesNumericCode;
40.156 + static int[] scNewCurrenciesNumericCode;
40.157 + static String otherCurrencies;
40.158 + static int[] otherCurrenciesDFD;
40.159 + static int[] otherCurrenciesNumericCode;
40.160 +
40.161 + // handy constants - must match definitions in GenerateCurrencyData
40.162 + // magic number
40.163 + private static final int MAGIC_NUMBER = 0x43757244;
40.164 + // number of characters from A to Z
40.165 + private static final int A_TO_Z = ('Z' - 'A') + 1;
40.166 + // entry for invalid country codes
40.167 + private static final int INVALID_COUNTRY_ENTRY = 0x007F;
40.168 + // entry for countries without currency
40.169 + private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x0080;
40.170 + // mask for simple case country entries
40.171 + private static final int SIMPLE_CASE_COUNTRY_MASK = 0x0000;
40.172 + // mask for simple case country entry final character
40.173 + private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x001F;
40.174 + // mask for simple case country entry default currency digits
40.175 + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x0060;
40.176 + // shift count for simple case country entry default currency digits
40.177 + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
40.178 + // mask for special case country entries
40.179 + private static final int SPECIAL_CASE_COUNTRY_MASK = 0x0080;
40.180 + // mask for special case country index
40.181 + private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x001F;
40.182 + // delta from entry index component in main table to index into special case tables
40.183 + private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
40.184 + // mask for distinguishing simple and special case countries
40.185 + private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
40.186 + // mask for the numeric code of the currency
40.187 + private static final int NUMERIC_CODE_MASK = 0x0003FF00;
40.188 + // shift count for the numeric code of the currency
40.189 + private static final int NUMERIC_CODE_SHIFT = 8;
40.190 +
40.191 + // Currency data format version
40.192 + private static final int VALID_FORMAT_VERSION = 1;
40.193 +
40.194 + static {
40.195 + AccessController.doPrivileged(new PrivilegedAction() {
40.196 + public Object run() {
40.197 + String homeDir = System.getProperty("java.home");
40.198 + try {
40.199 + String dataFile = homeDir + File.separator +
40.200 + "lib" + File.separator + "currency.data";
40.201 + DataInputStream dis = new DataInputStream(
40.202 + new BufferedInputStream(
40.203 + new FileInputStream(dataFile)));
40.204 + if (dis.readInt() != MAGIC_NUMBER) {
40.205 + throw new InternalError("Currency data is possibly corrupted");
40.206 + }
40.207 + formatVersion = dis.readInt();
40.208 + if (formatVersion != VALID_FORMAT_VERSION) {
40.209 + throw new InternalError("Currency data format is incorrect");
40.210 + }
40.211 + dataVersion = dis.readInt();
40.212 + mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
40.213 + int scCount = dis.readInt();
40.214 + scCutOverTimes = readLongArray(dis, scCount);
40.215 + scOldCurrencies = readStringArray(dis, scCount);
40.216 + scNewCurrencies = readStringArray(dis, scCount);
40.217 + scOldCurrenciesDFD = readIntArray(dis, scCount);
40.218 + scNewCurrenciesDFD = readIntArray(dis, scCount);
40.219 + scOldCurrenciesNumericCode = readIntArray(dis, scCount);
40.220 + scNewCurrenciesNumericCode = readIntArray(dis, scCount);
40.221 + int ocCount = dis.readInt();
40.222 + otherCurrencies = dis.readUTF();
40.223 + otherCurrenciesDFD = readIntArray(dis, ocCount);
40.224 + otherCurrenciesNumericCode = readIntArray(dis, ocCount);
40.225 + dis.close();
40.226 + } catch (IOException e) {
40.227 + InternalError ie = new InternalError();
40.228 + ie.initCause(e);
40.229 + throw ie;
40.230 + }
40.231 +
40.232 + // look for the properties file for overrides
40.233 + try {
40.234 + File propFile = new File(homeDir + File.separator +
40.235 + "lib" + File.separator +
40.236 + "currency.properties");
40.237 + if (propFile.exists()) {
40.238 + Properties props = new Properties();
40.239 + try (FileReader fr = new FileReader(propFile)) {
40.240 + props.load(fr);
40.241 + }
40.242 + Set<String> keys = props.stringPropertyNames();
40.243 + Pattern propertiesPattern =
40.244 + Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*([0-3])");
40.245 + for (String key : keys) {
40.246 + replaceCurrencyData(propertiesPattern,
40.247 + key.toUpperCase(Locale.ROOT),
40.248 + props.getProperty(key).toUpperCase(Locale.ROOT));
40.249 + }
40.250 + }
40.251 + } catch (IOException e) {
40.252 + info("currency.properties is ignored because of an IOException", e);
40.253 + }
40.254 + return null;
40.255 + }
40.256 + });
40.257 + }
40.258 +
40.259 + /**
40.260 + * Constants for retrieving localized names from the name providers.
40.261 + */
40.262 + private static final int SYMBOL = 0;
40.263 + private static final int DISPLAYNAME = 1;
40.264 +
40.265 +
40.266 + /**
40.267 + * Constructs a <code>Currency</code> instance. The constructor is private
40.268 + * so that we can insure that there's never more than one instance for a
40.269 + * given currency.
40.270 + */
40.271 + private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
40.272 + this.currencyCode = currencyCode;
40.273 + this.defaultFractionDigits = defaultFractionDigits;
40.274 + this.numericCode = numericCode;
40.275 + }
40.276 +
40.277 + /**
40.278 + * Returns the <code>Currency</code> instance for the given currency code.
40.279 + *
40.280 + * @param currencyCode the ISO 4217 code of the currency
40.281 + * @return the <code>Currency</code> instance for the given currency code
40.282 + * @exception NullPointerException if <code>currencyCode</code> is null
40.283 + * @exception IllegalArgumentException if <code>currencyCode</code> is not
40.284 + * a supported ISO 4217 code.
40.285 + */
40.286 + public static Currency getInstance(String currencyCode) {
40.287 + return getInstance(currencyCode, Integer.MIN_VALUE, 0);
40.288 + }
40.289 +
40.290 + private static Currency getInstance(String currencyCode, int defaultFractionDigits,
40.291 + int numericCode) {
40.292 + synchronized (instances) {
40.293 + // Try to look up the currency code in the instances table.
40.294 + // This does the null pointer check as a side effect.
40.295 + // Also, if there already is an entry, the currencyCode must be valid.
40.296 + Currency instance = instances.get(currencyCode);
40.297 + if (instance != null) {
40.298 + return instance;
40.299 + }
40.300 +
40.301 + if (defaultFractionDigits == Integer.MIN_VALUE) {
40.302 + // Currency code not internally generated, need to verify first
40.303 + // A currency code must have 3 characters and exist in the main table
40.304 + // or in the list of other currencies.
40.305 + if (currencyCode.length() != 3) {
40.306 + throw new IllegalArgumentException();
40.307 + }
40.308 + char char1 = currencyCode.charAt(0);
40.309 + char char2 = currencyCode.charAt(1);
40.310 + int tableEntry = getMainTableEntry(char1, char2);
40.311 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
40.312 + && tableEntry != INVALID_COUNTRY_ENTRY
40.313 + && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
40.314 + defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
40.315 + numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
40.316 + } else {
40.317 + // Check for '-' separately so we don't get false hits in the table.
40.318 + if (currencyCode.charAt(2) == '-') {
40.319 + throw new IllegalArgumentException();
40.320 + }
40.321 + int index = otherCurrencies.indexOf(currencyCode);
40.322 + if (index == -1) {
40.323 + throw new IllegalArgumentException();
40.324 + }
40.325 + defaultFractionDigits = otherCurrenciesDFD[index / 4];
40.326 + numericCode = otherCurrenciesNumericCode[index / 4];
40.327 + }
40.328 + }
40.329 +
40.330 + instance = new Currency(currencyCode, defaultFractionDigits, numericCode);
40.331 + instances.put(currencyCode, instance);
40.332 + return instance;
40.333 + }
40.334 + }
40.335 +
40.336 + /**
40.337 + * Returns the <code>Currency</code> instance for the country of the
40.338 + * given locale. The language and variant components of the locale
40.339 + * are ignored. The result may vary over time, as countries change their
40.340 + * currencies. For example, for the original member countries of the
40.341 + * European Monetary Union, the method returns the old national currencies
40.342 + * until December 31, 2001, and the Euro from January 1, 2002, local time
40.343 + * of the respective countries.
40.344 + * <p>
40.345 + * The method returns <code>null</code> for territories that don't
40.346 + * have a currency, such as Antarctica.
40.347 + *
40.348 + * @param locale the locale for whose country a <code>Currency</code>
40.349 + * instance is needed
40.350 + * @return the <code>Currency</code> instance for the country of the given
40.351 + * locale, or null
40.352 + * @exception NullPointerException if <code>locale</code> or its country
40.353 + * code is null
40.354 + * @exception IllegalArgumentException if the country of the given locale
40.355 + * is not a supported ISO 3166 country code.
40.356 + */
40.357 + public static Currency getInstance(Locale locale) {
40.358 + String country = locale.getCountry();
40.359 + if (country == null) {
40.360 + throw new NullPointerException();
40.361 + }
40.362 +
40.363 + if (country.length() != 2) {
40.364 + throw new IllegalArgumentException();
40.365 + }
40.366 +
40.367 + char char1 = country.charAt(0);
40.368 + char char2 = country.charAt(1);
40.369 + int tableEntry = getMainTableEntry(char1, char2);
40.370 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
40.371 + && tableEntry != INVALID_COUNTRY_ENTRY) {
40.372 + char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
40.373 + int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
40.374 + int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
40.375 + StringBuffer sb = new StringBuffer(country);
40.376 + sb.append(finalChar);
40.377 + return getInstance(sb.toString(), defaultFractionDigits, numericCode);
40.378 + } else {
40.379 + // special cases
40.380 + if (tableEntry == INVALID_COUNTRY_ENTRY) {
40.381 + throw new IllegalArgumentException();
40.382 + }
40.383 + if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
40.384 + return null;
40.385 + } else {
40.386 + int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
40.387 + if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
40.388 + return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
40.389 + scOldCurrenciesNumericCode[index]);
40.390 + } else {
40.391 + return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
40.392 + scNewCurrenciesNumericCode[index]);
40.393 + }
40.394 + }
40.395 + }
40.396 + }
40.397 +
40.398 + /**
40.399 + * Gets the set of available currencies. The returned set of currencies
40.400 + * contains all of the available currencies, which may include currencies
40.401 + * that represent obsolete ISO 4217 codes. The set can be modified
40.402 + * without affecting the available currencies in the runtime.
40.403 + *
40.404 + * @return the set of available currencies. If there is no currency
40.405 + * available in the runtime, the returned set is empty.
40.406 + * @since 1.7
40.407 + */
40.408 + public static Set<Currency> getAvailableCurrencies() {
40.409 + synchronized(Currency.class) {
40.410 + if (available == null) {
40.411 + available = new HashSet<Currency>(256);
40.412 +
40.413 + // Add simple currencies first
40.414 + for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
40.415 + for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
40.416 + int tableEntry = getMainTableEntry(c1, c2);
40.417 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
40.418 + && tableEntry != INVALID_COUNTRY_ENTRY) {
40.419 + char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
40.420 + int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
40.421 + int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
40.422 + StringBuilder sb = new StringBuilder();
40.423 + sb.append(c1);
40.424 + sb.append(c2);
40.425 + sb.append(finalChar);
40.426 + available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
40.427 + }
40.428 + }
40.429 + }
40.430 +
40.431 + // Now add other currencies
40.432 + StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
40.433 + while (st.hasMoreElements()) {
40.434 + available.add(getInstance((String)st.nextElement()));
40.435 + }
40.436 + }
40.437 + }
40.438 +
40.439 + return (Set<Currency>) available.clone();
40.440 + }
40.441 +
40.442 + /**
40.443 + * Gets the ISO 4217 currency code of this currency.
40.444 + *
40.445 + * @return the ISO 4217 currency code of this currency.
40.446 + */
40.447 + public String getCurrencyCode() {
40.448 + return currencyCode;
40.449 + }
40.450 +
40.451 + /**
40.452 + * Gets the symbol of this currency for the default locale.
40.453 + * For example, for the US Dollar, the symbol is "$" if the default
40.454 + * locale is the US, while for other locales it may be "US$". If no
40.455 + * symbol can be determined, the ISO 4217 currency code is returned.
40.456 + *
40.457 + * @return the symbol of this currency for the default locale
40.458 + */
40.459 + public String getSymbol() {
40.460 + return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
40.461 + }
40.462 +
40.463 + /**
40.464 + * Gets the symbol of this currency for the specified locale.
40.465 + * For example, for the US Dollar, the symbol is "$" if the specified
40.466 + * locale is the US, while for other locales it may be "US$". If no
40.467 + * symbol can be determined, the ISO 4217 currency code is returned.
40.468 + *
40.469 + * @param locale the locale for which a display name for this currency is
40.470 + * needed
40.471 + * @return the symbol of this currency for the specified locale
40.472 + * @exception NullPointerException if <code>locale</code> is null
40.473 + */
40.474 + public String getSymbol(Locale locale) {
40.475 + try {
40.476 + // Check whether a provider can provide an implementation that's closer
40.477 + // to the requested locale than what the Java runtime itself can provide.
40.478 + LocaleServiceProviderPool pool =
40.479 + LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
40.480 +
40.481 + if (pool.hasProviders()) {
40.482 + // Assuming that all the country locales include necessary currency
40.483 + // symbols in the Java runtime's resources, so there is no need to
40.484 + // examine whether Java runtime's currency resource bundle is missing
40.485 + // names. Therefore, no resource bundle is provided for calling this
40.486 + // method.
40.487 + String symbol = pool.getLocalizedObject(
40.488 + CurrencyNameGetter.INSTANCE,
40.489 + locale, (OpenListResourceBundle)null,
40.490 + currencyCode, SYMBOL);
40.491 + if (symbol != null) {
40.492 + return symbol;
40.493 + }
40.494 + }
40.495 +
40.496 + ResourceBundle bundle = LocaleData.getCurrencyNames(locale);
40.497 + return bundle.getString(currencyCode);
40.498 + } catch (MissingResourceException e) {
40.499 + // use currency code as symbol of last resort
40.500 + return currencyCode;
40.501 + }
40.502 + }
40.503 +
40.504 + /**
40.505 + * Gets the default number of fraction digits used with this currency.
40.506 + * For example, the default number of fraction digits for the Euro is 2,
40.507 + * while for the Japanese Yen it's 0.
40.508 + * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
40.509 + * -1 is returned.
40.510 + *
40.511 + * @return the default number of fraction digits used with this currency
40.512 + */
40.513 + public int getDefaultFractionDigits() {
40.514 + return defaultFractionDigits;
40.515 + }
40.516 +
40.517 + /**
40.518 + * Returns the ISO 4217 numeric code of this currency.
40.519 + *
40.520 + * @return the ISO 4217 numeric code of this currency
40.521 + * @since 1.7
40.522 + */
40.523 + public int getNumericCode() {
40.524 + return numericCode;
40.525 + }
40.526 +
40.527 + /**
40.528 + * Gets the name that is suitable for displaying this currency for
40.529 + * the default locale. If there is no suitable display name found
40.530 + * for the default locale, the ISO 4217 currency code is returned.
40.531 + *
40.532 + * @return the display name of this currency for the default locale
40.533 + * @since 1.7
40.534 + */
40.535 + public String getDisplayName() {
40.536 + return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
40.537 + }
40.538 +
40.539 + /**
40.540 + * Gets the name that is suitable for displaying this currency for
40.541 + * the specified locale. If there is no suitable display name found
40.542 + * for the specified locale, the ISO 4217 currency code is returned.
40.543 + *
40.544 + * @param locale the locale for which a display name for this currency is
40.545 + * needed
40.546 + * @return the display name of this currency for the specified locale
40.547 + * @exception NullPointerException if <code>locale</code> is null
40.548 + * @since 1.7
40.549 + */
40.550 + public String getDisplayName(Locale locale) {
40.551 + try {
40.552 + OpenListResourceBundle bundle = LocaleData.getCurrencyNames(locale);
40.553 + String result = null;
40.554 + String bundleKey = currencyCode.toLowerCase(Locale.ROOT);
40.555 +
40.556 + // Check whether a provider can provide an implementation that's closer
40.557 + // to the requested locale than what the Java runtime itself can provide.
40.558 + LocaleServiceProviderPool pool =
40.559 + LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
40.560 + if (pool.hasProviders()) {
40.561 + result = pool.getLocalizedObject(
40.562 + CurrencyNameGetter.INSTANCE,
40.563 + locale, bundleKey, bundle, currencyCode, DISPLAYNAME);
40.564 + }
40.565 +
40.566 + if (result == null) {
40.567 + result = bundle.getString(bundleKey);
40.568 + }
40.569 +
40.570 + if (result != null) {
40.571 + return result;
40.572 + }
40.573 + } catch (MissingResourceException e) {
40.574 + // fall through
40.575 + }
40.576 +
40.577 + // use currency code as symbol of last resort
40.578 + return currencyCode;
40.579 + }
40.580 +
40.581 + /**
40.582 + * Returns the ISO 4217 currency code of this currency.
40.583 + *
40.584 + * @return the ISO 4217 currency code of this currency
40.585 + */
40.586 + public String toString() {
40.587 + return currencyCode;
40.588 + }
40.589 +
40.590 + /**
40.591 + * Resolves instances being deserialized to a single instance per currency.
40.592 + */
40.593 + private Object readResolve() {
40.594 + return getInstance(currencyCode);
40.595 + }
40.596 +
40.597 + /**
40.598 + * Gets the main table entry for the country whose country code consists
40.599 + * of char1 and char2.
40.600 + */
40.601 + private static int getMainTableEntry(char char1, char char2) {
40.602 + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
40.603 + throw new IllegalArgumentException();
40.604 + }
40.605 + return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
40.606 + }
40.607 +
40.608 + /**
40.609 + * Sets the main table entry for the country whose country code consists
40.610 + * of char1 and char2.
40.611 + */
40.612 + private static void setMainTableEntry(char char1, char char2, int entry) {
40.613 + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
40.614 + throw new IllegalArgumentException();
40.615 + }
40.616 + mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
40.617 + }
40.618 +
40.619 + /**
40.620 + * Obtains a localized currency names from a CurrencyNameProvider
40.621 + * implementation.
40.622 + */
40.623 + private static class CurrencyNameGetter
40.624 + implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
40.625 + String> {
40.626 + private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
40.627 +
40.628 + public String getObject(CurrencyNameProvider currencyNameProvider,
40.629 + Locale locale,
40.630 + String key,
40.631 + Object... params) {
40.632 + assert params.length == 1;
40.633 + int type = (Integer)params[0];
40.634 +
40.635 + switch(type) {
40.636 + case SYMBOL:
40.637 + return currencyNameProvider.getSymbol(key, locale);
40.638 + case DISPLAYNAME:
40.639 + return currencyNameProvider.getDisplayName(key, locale);
40.640 + default:
40.641 + assert false; // shouldn't happen
40.642 + }
40.643 +
40.644 + return null;
40.645 + }
40.646 + }
40.647 +
40.648 + private static int[] readIntArray(DataInputStream dis, int count) throws IOException {
40.649 + int[] ret = new int[count];
40.650 + for (int i = 0; i < count; i++) {
40.651 + ret[i] = dis.readInt();
40.652 + }
40.653 +
40.654 + return ret;
40.655 + }
40.656 +
40.657 + private static long[] readLongArray(DataInputStream dis, int count) throws IOException {
40.658 + long[] ret = new long[count];
40.659 + for (int i = 0; i < count; i++) {
40.660 + ret[i] = dis.readLong();
40.661 + }
40.662 +
40.663 + return ret;
40.664 + }
40.665 +
40.666 + private static String[] readStringArray(DataInputStream dis, int count) throws IOException {
40.667 + String[] ret = new String[count];
40.668 + for (int i = 0; i < count; i++) {
40.669 + ret[i] = dis.readUTF();
40.670 + }
40.671 +
40.672 + return ret;
40.673 + }
40.674 +
40.675 + /**
40.676 + * Replaces currency data found in the currencydata.properties file
40.677 + *
40.678 + * @param pattern regex pattern for the properties
40.679 + * @param ctry country code
40.680 + * @param data currency data. This is a comma separated string that
40.681 + * consists of "three-letter alphabet code", "three-digit numeric code",
40.682 + * and "one-digit (0,1,2, or 3) default fraction digit".
40.683 + * For example, "JPZ,392,0".
40.684 + * @throws
40.685 + */
40.686 + private static void replaceCurrencyData(Pattern pattern, String ctry, String curdata) {
40.687 +
40.688 + if (ctry.length() != 2) {
40.689 + // ignore invalid country code
40.690 + String message = new StringBuilder()
40.691 + .append("The entry in currency.properties for ")
40.692 + .append(ctry).append(" is ignored because of the invalid country code.")
40.693 + .toString();
40.694 + info(message, null);
40.695 + return;
40.696 + }
40.697 +
40.698 + Matcher m = pattern.matcher(curdata);
40.699 + if (!m.find()) {
40.700 + // format is not recognized. ignore the data
40.701 + String message = new StringBuilder()
40.702 + .append("The entry in currency.properties for ")
40.703 + .append(ctry)
40.704 + .append(" is ignored because the value format is not recognized.")
40.705 + .toString();
40.706 + info(message, null);
40.707 + return;
40.708 + }
40.709 +
40.710 + String code = m.group(1);
40.711 + int numeric = Integer.parseInt(m.group(2));
40.712 + int fraction = Integer.parseInt(m.group(3));
40.713 + int entry = numeric << NUMERIC_CODE_SHIFT;
40.714 +
40.715 + int index;
40.716 + for (index = 0; index < scOldCurrencies.length; index++) {
40.717 + if (scOldCurrencies[index].equals(code)) {
40.718 + break;
40.719 + }
40.720 + }
40.721 +
40.722 + if (index == scOldCurrencies.length) {
40.723 + // simple case
40.724 + entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) |
40.725 + (code.charAt(2) - 'A');
40.726 + } else {
40.727 + // special case
40.728 + entry |= SPECIAL_CASE_COUNTRY_MASK |
40.729 + (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
40.730 + }
40.731 + setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
40.732 + }
40.733 +
40.734 + private static void info(String message, Throwable t) {
40.735 + PlatformLogger logger = PlatformLogger.getLogger("java.util.Currency");
40.736 + if (logger.isLoggable(PlatformLogger.INFO)) {
40.737 + if (t != null) {
40.738 + logger.info(message, t);
40.739 + } else {
40.740 + logger.info(message);
40.741 + }
40.742 + }
40.743 + }
40.744 +}
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/rt/emul/compact/src/main/java/java/util/CurrencyData.properties Thu Oct 03 15:40:35 2013 +0200
41.3 @@ -0,0 +1,586 @@
41.4 +#
41.5 +# Copyright (c) 2000, 2008, 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 +formatVersion=1
41.30 +
41.31 +# Version of the currency code information in this class.
41.32 +# It is a serial number that accompanies with each amendment, such as
41.33 +# 'MAxxx.doc'
41.34 +
41.35 +dataVersion=140
41.36 +
41.37 +# List of all valid ISO 4217 currency codes.
41.38 +# To ensure compatibility, do not remove codes.
41.39 +
41.40 +all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036-\
41.41 + AWG533-AYM945-AZM031-AZN944-BAM977-BBD052-BDT050-BEF056-BGL100-BGN975-BHD048-BIF108-\
41.42 + BMD060-BND096-BOB068-BOV984-BRL986-BSD044-BTN064-BWP072-BYB112-BYR974-\
41.43 + BZD084-CAD124-CDF976-CHF756-CLF990-CLP152-CNY156-COP170-CRC188-CSD891-CUP192-\
41.44 + CVE132-CYP196-CZK203-DEM276-DJF262-DKK208-DOP214-DZD012-EEK233-EGP818-\
41.45 + ERN232-ESP724-ETB230-EUR978-FIM246-FJD242-FKP238-FRF250-GBP826-GEL981-\
41.46 + GHC288-GHS936-GIP292-GMD270-GNF324-GRD300-GTQ320-GWP624-GYD328-HKD344-HNL340-\
41.47 + HRK191-HTG332-HUF348-IDR360-IEP372-ILS376-INR356-IQD368-IRR364-ISK352-\
41.48 + ITL380-JMD388-JOD400-JPY392-KES404-KGS417-KHR116-KMF174-KPW408-KRW410-\
41.49 + KWD414-KYD136-KZT398-LAK418-LBP422-LKR144-LRD430-LSL426-LTL440-LUF442-\
41.50 + LVL428-LYD434-MAD504-MDL498-MGA969-MGF450-MKD807-MMK104-MNT496-MOP446-MRO478-\
41.51 + MTL470-MUR480-MVR462-MWK454-MXN484-MXV979-MYR458-MZM508-MZN943-NAD516-NGN566-\
41.52 + NIO558-NLG528-NOK578-NPR524-NZD554-OMR512-PAB590-PEN604-PGK598-PHP608-\
41.53 + PKR586-PLN985-PTE620-PYG600-QAR634-ROL946-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\
41.54 + SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\
41.55 + SRD968-SRG740-STD678-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TND788-TOP776-\
41.56 + TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-\
41.57 + UYU858-UZS860-VEB862-VEF937-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\
41.58 + XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\
41.59 + XPT962-XTS963-XXX999-YER886-YUM891-ZAR710-ZMK894-ZWD716-ZWN942
41.60 +
41.61 +
41.62 +# Mappings from ISO 3166 country codes to ISO 4217 currency codes.
41.63 +#
41.64 +# Three forms are used:
41.65 +# Form 1: <country code>=<currency code>
41.66 +# Form 2: <country code>=<currency code 1>;<time stamp>;<currency code 2>
41.67 +# Form 3: <country code>=
41.68 +# Form 1 is used if no future change in currency is known.
41.69 +# Form 2 indicates that before the specified time currency 1 is used, from
41.70 +# the specified time currency 2. The time is given in SimpleDateFormat's
41.71 +# yyyy-MM-dd-HH-mm-ss format in the GMT time zone.
41.72 +# Form 3 indicates the country doesn't have a currency (the entry is still
41.73 +# needed to verify that the country code is valid).
41.74 +#
41.75 +# The table is based on the following web sites:
41.76 +# http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/db_en.html
41.77 +# http://www.bsi-global.com/iso4217currency
41.78 +# http://www.cia.gov/cia/publications/factbook/indexgeo.html
41.79 +
41.80 +# AFGHANISTAN
41.81 +AF=AFN
41.82 +# \u00c5LAND ISLANDS
41.83 +AX=EUR
41.84 +# ALBANIA
41.85 +AL=ALL
41.86 +# ALGERIA
41.87 +DZ=DZD
41.88 +# AMERICAN SAMOA
41.89 +AS=USD
41.90 +# ANDORRA
41.91 +AD=EUR
41.92 +# ANGOLA
41.93 +AO=AOA
41.94 +# ANGUILLA
41.95 +AI=XCD
41.96 +# ANTARCTICA
41.97 +AQ=
41.98 +# ANTIGUA AND BARBUDA
41.99 +AG=XCD
41.100 +# ARGENTINA
41.101 +AR=ARS
41.102 +# ARMENIA
41.103 +AM=AMD
41.104 +# ARUBA
41.105 +AW=AWG
41.106 +# AUSTRALIA
41.107 +AU=AUD
41.108 +# AUSTRIA
41.109 +AT=EUR
41.110 +# AZERBAIJAN
41.111 +AZ=AZM;2005-12-31-20-00-00;AZN
41.112 +# BAHAMAS
41.113 +BS=BSD
41.114 +# BAHRAIN
41.115 +BH=BHD
41.116 +# BANGLADESH
41.117 +BD=BDT
41.118 +# BARBADOS
41.119 +BB=BBD
41.120 +# BELARUS
41.121 +BY=BYR
41.122 +# BELGIUM
41.123 +BE=EUR
41.124 +# BELIZE
41.125 +BZ=BZD
41.126 +# BENIN
41.127 +BJ=XOF
41.128 +# BERMUDA
41.129 +BM=BMD
41.130 +# BHUTAN
41.131 +BT=BTN
41.132 +# BOLIVIA
41.133 +BO=BOB
41.134 +# BOSNIA AND HERZEGOVINA
41.135 +BA=BAM
41.136 +# BOTSWANA
41.137 +BW=BWP
41.138 +# BOUVET ISLAND
41.139 +BV=NOK
41.140 +# BRAZIL
41.141 +BR=BRL
41.142 +# BRITISH INDIAN OCEAN TERRITORY
41.143 +IO=USD
41.144 +# BRUNEI DARUSSALAM
41.145 +BN=BND
41.146 +# BULGARIA
41.147 +BG=BGN
41.148 +# BURKINA FASO
41.149 +BF=XOF
41.150 +# BURUNDI
41.151 +BI=BIF
41.152 +# CAMBODIA
41.153 +KH=KHR
41.154 +# CAMEROON
41.155 +CM=XAF
41.156 +# CANADA
41.157 +CA=CAD
41.158 +# CAPE VERDE
41.159 +CV=CVE
41.160 +# CAYMAN ISLANDS
41.161 +KY=KYD
41.162 +# CENTRAL AFRICAN REPUBLIC
41.163 +CF=XAF
41.164 +# CHAD
41.165 +TD=XAF
41.166 +# CHILE
41.167 +CL=CLP
41.168 +# CHINA
41.169 +CN=CNY
41.170 +# CHRISTMAS ISLAND
41.171 +CX=AUD
41.172 +# COCOS (KEELING) ISLANDS
41.173 +CC=AUD
41.174 +# COLOMBIA
41.175 +CO=COP
41.176 +# COMOROS
41.177 +KM=KMF
41.178 +# CONGO
41.179 +CG=XAF
41.180 +# CONGO, THE DEMOCRATIC REPUBLIC OF THE
41.181 +CD=CDF
41.182 +# COOK ISLANDS
41.183 +CK=NZD
41.184 +# COSTA RICA
41.185 +CR=CRC
41.186 +# COTE D'IVOIRE
41.187 +CI=XOF
41.188 +# CROATIA
41.189 +HR=HRK
41.190 +# CUBA
41.191 +CU=CUP
41.192 +# CYPRUS
41.193 +CY=EUR
41.194 +# CZECH REPUBLIC
41.195 +CZ=CZK
41.196 +# DENMARK
41.197 +DK=DKK
41.198 +# DJIBOUTI
41.199 +DJ=DJF
41.200 +# DOMINICA
41.201 +DM=XCD
41.202 +# DOMINICAN REPUBLIC
41.203 +DO=DOP
41.204 +# ECUADOR
41.205 +EC=USD
41.206 +# EGYPT
41.207 +EG=EGP
41.208 +# EL SALVADOR
41.209 +# USD is also legal currency as of 2001/01/01
41.210 +SV=SVC
41.211 +# EQUATORIAL GUINEA
41.212 +GQ=XAF
41.213 +# ERITREA
41.214 +ER=ERN
41.215 +# ESTONIA
41.216 +EE=EEK
41.217 +# ETHIOPIA
41.218 +ET=ETB
41.219 +# FALKLAND ISLANDS (MALVINAS)
41.220 +FK=FKP
41.221 +# FAROE ISLANDS
41.222 +FO=DKK
41.223 +# FIJI
41.224 +FJ=FJD
41.225 +# FINLAND
41.226 +FI=EUR
41.227 +# FRANCE
41.228 +FR=EUR
41.229 +# FRENCH GUIANA
41.230 +GF=EUR
41.231 +# FRENCH POLYNESIA
41.232 +PF=XPF
41.233 +# FRENCH SOUTHERN TERRITORIES
41.234 +TF=EUR
41.235 +# GABON
41.236 +GA=XAF
41.237 +# GAMBIA
41.238 +GM=GMD
41.239 +# GEORGIA
41.240 +GE=GEL
41.241 +# GERMANY
41.242 +DE=EUR
41.243 +# GHANA
41.244 +GH=GHS
41.245 +# GIBRALTAR
41.246 +GI=GIP
41.247 +# GREECE
41.248 +GR=EUR
41.249 +# GREENLAND
41.250 +GL=DKK
41.251 +# GRENADA
41.252 +GD=XCD
41.253 +# GUADELOUPE
41.254 +GP=EUR
41.255 +# GUAM
41.256 +GU=USD
41.257 +# GUATEMALA
41.258 +GT=GTQ
41.259 +# GUERNSEY
41.260 +GG=GBP
41.261 +# GUINEA
41.262 +GN=GNF
41.263 +# GUINEA-BISSAU
41.264 +GW=XOF
41.265 +# GUYANA
41.266 +GY=GYD
41.267 +# HAITI
41.268 +HT=HTG
41.269 +# HEARD ISLAND AND MCDONALD ISLANDS
41.270 +HM=AUD
41.271 +# HOLY SEE (VATICAN CITY STATE)
41.272 +VA=EUR
41.273 +# HONDURAS
41.274 +HN=HNL
41.275 +# HONG KONG
41.276 +HK=HKD
41.277 +# HUNGARY
41.278 +HU=HUF
41.279 +# ICELAND
41.280 +IS=ISK
41.281 +# INDIA
41.282 +IN=INR
41.283 +# INDONESIA
41.284 +ID=IDR
41.285 +# IRAN, ISLAMIC REPUBLIC OF
41.286 +IR=IRR
41.287 +# IRAQ
41.288 +IQ=IQD
41.289 +# IRELAND
41.290 +IE=EUR
41.291 +# ISLE OF MAN
41.292 +IM=GBP
41.293 +# ISRAEL
41.294 +IL=ILS
41.295 +# ITALY
41.296 +IT=EUR
41.297 +# JAMAICA
41.298 +JM=JMD
41.299 +# JAPAN
41.300 +JP=JPY
41.301 +# JERSEY
41.302 +JE=GBP
41.303 +# JORDAN
41.304 +JO=JOD
41.305 +# KAZAKSTAN
41.306 +KZ=KZT
41.307 +# KENYA
41.308 +KE=KES
41.309 +# KIRIBATI
41.310 +KI=AUD
41.311 +# KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF
41.312 +KP=KPW
41.313 +# KOREA, REPUBLIC OF
41.314 +KR=KRW
41.315 +# KUWAIT
41.316 +KW=KWD
41.317 +# KYRGYZSTAN
41.318 +KG=KGS
41.319 +# LAO PEOPLE'S DEMOCRATIC REPUBLIC
41.320 +LA=LAK
41.321 +# LATVIA
41.322 +LV=LVL
41.323 +# LEBANON
41.324 +LB=LBP
41.325 +# LESOTHO
41.326 +LS=LSL
41.327 +# LIBERIA
41.328 +LR=LRD
41.329 +# LIBYAN ARAB JAMAHIRIYA
41.330 +LY=LYD
41.331 +# LIECHTENSTEIN
41.332 +LI=CHF
41.333 +# LITHUANIA
41.334 +LT=LTL
41.335 +# LUXEMBOURG
41.336 +LU=EUR
41.337 +# MACAU
41.338 +MO=MOP
41.339 +# MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF
41.340 +MK=MKD
41.341 +# MADAGASCAR
41.342 +MG=MGA
41.343 +# MALAWI
41.344 +MW=MWK
41.345 +# MALAYSIA
41.346 +MY=MYR
41.347 +# MALDIVES
41.348 +MV=MVR
41.349 +# MALI
41.350 +ML=XOF
41.351 +# MALTA
41.352 +MT=EUR
41.353 +# MARSHALL ISLANDS
41.354 +MH=USD
41.355 +# MARTINIQUE
41.356 +MQ=EUR
41.357 +# MAURITANIA
41.358 +MR=MRO
41.359 +# MAURITIUS
41.360 +MU=MUR
41.361 +# MAYOTTE
41.362 +YT=EUR
41.363 +# MEXICO
41.364 +MX=MXN
41.365 +# MICRONESIA, FEDERATED STATES OF
41.366 +FM=USD
41.367 +# MOLDOVA, REPUBLIC OF
41.368 +MD=MDL
41.369 +# MONACO
41.370 +MC=EUR
41.371 +# MONGOLIA
41.372 +MN=MNT
41.373 +# MONTENEGRO
41.374 +ME=EUR
41.375 +# MONTSERRAT
41.376 +MS=XCD
41.377 +# MOROCCO
41.378 +MA=MAD
41.379 +# MOZAMBIQUE
41.380 +MZ=MZM;2006-06-30-22-00-00;MZN
41.381 +# MYANMAR
41.382 +MM=MMK
41.383 +# NAMIBIA
41.384 +NA=NAD
41.385 +# NAURU
41.386 +NR=AUD
41.387 +# NEPAL
41.388 +NP=NPR
41.389 +# NETHERLANDS
41.390 +NL=EUR
41.391 +# NETHERLANDS ANTILLES
41.392 +AN=ANG
41.393 +# NEW CALEDONIA
41.394 +NC=XPF
41.395 +# NEW ZEALAND
41.396 +NZ=NZD
41.397 +# NICARAGUA
41.398 +NI=NIO
41.399 +# NIGER
41.400 +NE=XOF
41.401 +# NIGERIA
41.402 +NG=NGN
41.403 +# NIUE
41.404 +NU=NZD
41.405 +# NORFOLK ISLAND
41.406 +NF=AUD
41.407 +# NORTHERN MARIANA ISLANDS
41.408 +MP=USD
41.409 +# NORWAY
41.410 +NO=NOK
41.411 +# OMAN
41.412 +OM=OMR
41.413 +# PAKISTAN
41.414 +PK=PKR
41.415 +# PALAU
41.416 +PW=USD
41.417 +# PALESTINIAN TERRITORY, OCCUPIED
41.418 +PS=ILS
41.419 +# PANAMA
41.420 +PA=PAB
41.421 +# PAPUA NEW GUINEA
41.422 +PG=PGK
41.423 +# PARAGUAY
41.424 +PY=PYG
41.425 +# PERU
41.426 +PE=PEN
41.427 +# PHILIPPINES
41.428 +PH=PHP
41.429 +# PITCAIRN
41.430 +PN=NZD
41.431 +# POLAND
41.432 +PL=PLN
41.433 +# PORTUGAL
41.434 +PT=EUR
41.435 +# PUERTO RICO
41.436 +PR=USD
41.437 +# QATAR
41.438 +QA=QAR
41.439 +# REUNION
41.440 +RE=EUR
41.441 +# ROMANIA
41.442 +RO=ROL;2005-06-30-21-00-00;RON
41.443 +# RUSSIAN FEDERATION
41.444 +RU=RUB
41.445 +# RWANDA
41.446 +RW=RWF
41.447 +# SAINT BARTHELEMY
41.448 +BL=EUR
41.449 +# SAINT HELENA
41.450 +SH=SHP
41.451 +# SAINT KITTS AND NEVIS
41.452 +KN=XCD
41.453 +# SAINT LUCIA
41.454 +LC=XCD
41.455 +# SAINT MARTIN
41.456 +MF=EUR
41.457 +# SAINT PIERRE AND MIQUELON
41.458 +PM=EUR
41.459 +# SAINT VINCENT AND THE GRENADINES
41.460 +VC=XCD
41.461 +# SAMOA
41.462 +WS=WST
41.463 +# SAN MARINO
41.464 +SM=EUR
41.465 +# SAO TOME AND PRINCIPE
41.466 +ST=STD
41.467 +# SAUDI ARABIA
41.468 +SA=SAR
41.469 +# SENEGAL
41.470 +SN=XOF
41.471 +# SERBIA
41.472 +RS=RSD
41.473 +# SERBIA AND MONTENEGRO
41.474 +CS=CSD
41.475 +# SEYCHELLES
41.476 +SC=SCR
41.477 +# SIERRA LEONE
41.478 +SL=SLL
41.479 +# SINGAPORE
41.480 +SG=SGD
41.481 +# SLOVAKIA
41.482 +SK=SKK
41.483 +# SLOVENIA
41.484 +SI=EUR
41.485 +# SOLOMON ISLANDS
41.486 +SB=SBD
41.487 +# SOMALIA
41.488 +SO=SOS
41.489 +# SOUTH AFRICA
41.490 +ZA=ZAR
41.491 +# SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS
41.492 +GS=GBP
41.493 +# SPAIN
41.494 +ES=EUR
41.495 +# SRI LANKA
41.496 +LK=LKR
41.497 +# SUDAN
41.498 +SD=SDG
41.499 +# SURINAME
41.500 +SR=SRD
41.501 +# SVALBARD AND JAN MAYEN
41.502 +SJ=NOK
41.503 +# SWAZILAND
41.504 +SZ=SZL
41.505 +# SWEDEN
41.506 +SE=SEK
41.507 +# SWITZERLAND
41.508 +CH=CHF
41.509 +# SYRIAN ARAB REPUBLIC
41.510 +SY=SYP
41.511 +# TAIWAN
41.512 +TW=TWD
41.513 +# TAJIKISTAN
41.514 +TJ=TJS
41.515 +# TANZANIA, UNITED REPUBLIC OF
41.516 +TZ=TZS
41.517 +# THAILAND
41.518 +TH=THB
41.519 +# TIMOR-LESTE
41.520 +TL=USD
41.521 +# TOGO
41.522 +TG=XOF
41.523 +# TOKELAU
41.524 +TK=NZD
41.525 +# TONGA
41.526 +TO=TOP
41.527 +# TRINIDAD AND TOBAGO
41.528 +TT=TTD
41.529 +# TUNISIA
41.530 +TN=TND
41.531 +# TURKEY
41.532 +TR=TRL;2004-12-31-22-00-00;TRY
41.533 +# TURKMENISTAN
41.534 +TM=TMM
41.535 +# TURKS AND CAICOS ISLANDS
41.536 +TC=USD
41.537 +# TUVALU
41.538 +TV=AUD
41.539 +# UGANDA
41.540 +UG=UGX
41.541 +# UKRAINE
41.542 +UA=UAH
41.543 +# UNITED ARAB EMIRATES
41.544 +AE=AED
41.545 +# UNITED KINGDOM
41.546 +GB=GBP
41.547 +# UNITED STATES
41.548 +US=USD
41.549 +# UNITED STATES MINOR OUTLYING ISLANDS
41.550 +UM=USD
41.551 +# URUGUAY
41.552 +UY=UYU
41.553 +# UZBEKISTAN
41.554 +UZ=UZS
41.555 +# VANUATU
41.556 +VU=VUV
41.557 +# VENEZUELA
41.558 +VE=VEB;2008-01-01-04-00-00;VEF
41.559 +# VIET NAM
41.560 +VN=VND
41.561 +# VIRGIN ISLANDS, BRITISH
41.562 +VG=USD
41.563 +# VIRGIN ISLANDS, U.S.
41.564 +VI=USD
41.565 +# WALLIS AND FUTUNA
41.566 +WF=XPF
41.567 +# WESTERN SAHARA
41.568 +EH=MAD
41.569 +# YEMEN
41.570 +YE=YER
41.571 +# ZAMBIA
41.572 +ZM=ZMK
41.573 +# ZIMBABWE
41.574 +ZW=ZWD
41.575 +
41.576 +
41.577 +# List of currencies with 0, 1, OR 3 decimals for minor units, or where there
41.578 +# are no minor units defined. All others use 2 decimals.
41.579 +
41.580 +minor0=\
41.581 + ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\
41.582 + GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
41.583 + TPE-TRL-VUV-XAF-XOF-XPF
41.584 +minor1=
41.585 +minor3=\
41.586 + BHD-IQD-JOD-KWD-LYD-OMR-TND
41.587 +minorUndefined=\
41.588 + XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-\
41.589 + XPT-XTS-XXX
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/rt/emul/compact/src/main/java/java/util/Date.java Thu Oct 03 15:40:35 2013 +0200
42.3 @@ -0,0 +1,1331 @@
42.4 +/*
42.5 + * Copyright (c) 1994, 2010, 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.text.DateFormat;
42.32 +import java.io.IOException;
42.33 +import java.io.ObjectOutputStream;
42.34 +import java.io.ObjectInputStream;
42.35 +import java.lang.ref.SoftReference;
42.36 +import sun.util.calendar.BaseCalendar;
42.37 +import sun.util.calendar.CalendarDate;
42.38 +import sun.util.calendar.CalendarSystem;
42.39 +import sun.util.calendar.CalendarUtils;
42.40 +import sun.util.calendar.Era;
42.41 +import sun.util.calendar.Gregorian;
42.42 +import sun.util.calendar.ZoneInfo;
42.43 +
42.44 +/**
42.45 + * The class <code>Date</code> represents a specific instant
42.46 + * in time, with millisecond precision.
42.47 + * <p>
42.48 + * Prior to JDK 1.1, the class <code>Date</code> had two additional
42.49 + * functions. It allowed the interpretation of dates as year, month, day, hour,
42.50 + * minute, and second values. It also allowed the formatting and parsing
42.51 + * of date strings. Unfortunately, the API for these functions was not
42.52 + * amenable to internationalization. As of JDK 1.1, the
42.53 + * <code>Calendar</code> class should be used to convert between dates and time
42.54 + * fields and the <code>DateFormat</code> class should be used to format and
42.55 + * parse date strings.
42.56 + * The corresponding methods in <code>Date</code> are deprecated.
42.57 + * <p>
42.58 + * Although the <code>Date</code> class is intended to reflect
42.59 + * coordinated universal time (UTC), it may not do so exactly,
42.60 + * depending on the host environment of the Java Virtual Machine.
42.61 + * Nearly all modern operating systems assume that 1 day =
42.62 + * 24 × 60 × 60 = 86400 seconds
42.63 + * in all cases. In UTC, however, about once every year or two there
42.64 + * is an extra second, called a "leap second." The leap
42.65 + * second is always added as the last second of the day, and always
42.66 + * on December 31 or June 30. For example, the last minute of the
42.67 + * year 1995 was 61 seconds long, thanks to an added leap second.
42.68 + * Most computer clocks are not accurate enough to be able to reflect
42.69 + * the leap-second distinction.
42.70 + * <p>
42.71 + * Some computer standards are defined in terms of Greenwich mean
42.72 + * time (GMT), which is equivalent to universal time (UT). GMT is
42.73 + * the "civil" name for the standard; UT is the
42.74 + * "scientific" name for the same standard. The
42.75 + * distinction between UTC and UT is that UTC is based on an atomic
42.76 + * clock and UT is based on astronomical observations, which for all
42.77 + * practical purposes is an invisibly fine hair to split. Because the
42.78 + * earth's rotation is not uniform (it slows down and speeds up
42.79 + * in complicated ways), UT does not always flow uniformly. Leap
42.80 + * seconds are introduced as needed into UTC so as to keep UTC within
42.81 + * 0.9 seconds of UT1, which is a version of UT with certain
42.82 + * corrections applied. There are other time and date systems as
42.83 + * well; for example, the time scale used by the satellite-based
42.84 + * global positioning system (GPS) is synchronized to UTC but is
42.85 + * <i>not</i> adjusted for leap seconds. An interesting source of
42.86 + * further information is the U.S. Naval Observatory, particularly
42.87 + * the Directorate of Time at:
42.88 + * <blockquote><pre>
42.89 + * <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
42.90 + * </pre></blockquote>
42.91 + * <p>
42.92 + * and their definitions of "Systems of Time" at:
42.93 + * <blockquote><pre>
42.94 + * <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
42.95 + * </pre></blockquote>
42.96 + * <p>
42.97 + * In all methods of class <code>Date</code> that accept or return
42.98 + * year, month, date, hours, minutes, and seconds values, the
42.99 + * following representations are used:
42.100 + * <ul>
42.101 + * <li>A year <i>y</i> is represented by the integer
42.102 + * <i>y</i> <code>- 1900</code>.
42.103 + * <li>A month is represented by an integer from 0 to 11; 0 is January,
42.104 + * 1 is February, and so forth; thus 11 is December.
42.105 + * <li>A date (day of month) is represented by an integer from 1 to 31
42.106 + * in the usual manner.
42.107 + * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
42.108 + * from midnight to 1 a.m. is hour 0, and the hour from noon to 1
42.109 + * p.m. is hour 12.
42.110 + * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
42.111 + * <li>A second is represented by an integer from 0 to 61; the values 60 and
42.112 + * 61 occur only for leap seconds and even then only in Java
42.113 + * implementations that actually track leap seconds correctly. Because
42.114 + * of the manner in which leap seconds are currently introduced, it is
42.115 + * extremely unlikely that two leap seconds will occur in the same
42.116 + * minute, but this specification follows the date and time conventions
42.117 + * for ISO C.
42.118 + * </ul>
42.119 + * <p>
42.120 + * In all cases, arguments given to methods for these purposes need
42.121 + * not fall within the indicated ranges; for example, a date may be
42.122 + * specified as January 32 and is interpreted as meaning February 1.
42.123 + *
42.124 + * @author James Gosling
42.125 + * @author Arthur van Hoff
42.126 + * @author Alan Liu
42.127 + * @see java.text.DateFormat
42.128 + * @see java.util.Calendar
42.129 + * @see java.util.TimeZone
42.130 + * @since JDK1.0
42.131 + */
42.132 +public class Date
42.133 + implements java.io.Serializable, Cloneable, Comparable<Date>
42.134 +{
42.135 + private static final BaseCalendar gcal =
42.136 + CalendarSystem.getGregorianCalendar();
42.137 + private static BaseCalendar jcal;
42.138 +
42.139 + private transient long fastTime;
42.140 +
42.141 + /*
42.142 + * If cdate is null, then fastTime indicates the time in millis.
42.143 + * If cdate.isNormalized() is true, then fastTime and cdate are in
42.144 + * synch. Otherwise, fastTime is ignored, and cdate indicates the
42.145 + * time.
42.146 + */
42.147 + private transient BaseCalendar.Date cdate;
42.148 +
42.149 + // Initialized just before the value is used. See parse().
42.150 + private static int defaultCenturyStart;
42.151 +
42.152 + /* use serialVersionUID from modified java.util.Date for
42.153 + * interoperability with JDK1.1. The Date was modified to write
42.154 + * and read only the UTC time.
42.155 + */
42.156 + private static final long serialVersionUID = 7523967970034938905L;
42.157 +
42.158 + /**
42.159 + * Allocates a <code>Date</code> object and initializes it so that
42.160 + * it represents the time at which it was allocated, measured to the
42.161 + * nearest millisecond.
42.162 + *
42.163 + * @see java.lang.System#currentTimeMillis()
42.164 + */
42.165 + public Date() {
42.166 + this(System.currentTimeMillis());
42.167 + }
42.168 +
42.169 + /**
42.170 + * Allocates a <code>Date</code> object and initializes it to
42.171 + * represent the specified number of milliseconds since the
42.172 + * standard base time known as "the epoch", namely January 1,
42.173 + * 1970, 00:00:00 GMT.
42.174 + *
42.175 + * @param date the milliseconds since January 1, 1970, 00:00:00 GMT.
42.176 + * @see java.lang.System#currentTimeMillis()
42.177 + */
42.178 + public Date(long date) {
42.179 + fastTime = date;
42.180 + }
42.181 +
42.182 + /**
42.183 + * Allocates a <code>Date</code> object and initializes it so that
42.184 + * it represents midnight, local time, at the beginning of the day
42.185 + * specified by the <code>year</code>, <code>month</code>, and
42.186 + * <code>date</code> arguments.
42.187 + *
42.188 + * @param year the year minus 1900.
42.189 + * @param month the month between 0-11.
42.190 + * @param date the day of the month between 1-31.
42.191 + * @see java.util.Calendar
42.192 + * @deprecated As of JDK version 1.1,
42.193 + * replaced by <code>Calendar.set(year + 1900, month, date)</code>
42.194 + * or <code>GregorianCalendar(year + 1900, month, date)</code>.
42.195 + */
42.196 + @Deprecated
42.197 + public Date(int year, int month, int date) {
42.198 + this(year, month, date, 0, 0, 0);
42.199 + }
42.200 +
42.201 + /**
42.202 + * Allocates a <code>Date</code> object and initializes it so that
42.203 + * it represents the instant at the start of the minute specified by
42.204 + * the <code>year</code>, <code>month</code>, <code>date</code>,
42.205 + * <code>hrs</code>, and <code>min</code> arguments, in the local
42.206 + * time zone.
42.207 + *
42.208 + * @param year the year minus 1900.
42.209 + * @param month the month between 0-11.
42.210 + * @param date the day of the month between 1-31.
42.211 + * @param hrs the hours between 0-23.
42.212 + * @param min the minutes between 0-59.
42.213 + * @see java.util.Calendar
42.214 + * @deprecated As of JDK version 1.1,
42.215 + * replaced by <code>Calendar.set(year + 1900, month, date,
42.216 + * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
42.217 + * month, date, hrs, min)</code>.
42.218 + */
42.219 + @Deprecated
42.220 + public Date(int year, int month, int date, int hrs, int min) {
42.221 + this(year, month, date, hrs, min, 0);
42.222 + }
42.223 +
42.224 + /**
42.225 + * Allocates a <code>Date</code> object and initializes it so that
42.226 + * it represents the instant at the start of the second specified
42.227 + * by the <code>year</code>, <code>month</code>, <code>date</code>,
42.228 + * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
42.229 + * in the local time zone.
42.230 + *
42.231 + * @param year the year minus 1900.
42.232 + * @param month the month between 0-11.
42.233 + * @param date the day of the month between 1-31.
42.234 + * @param hrs the hours between 0-23.
42.235 + * @param min the minutes between 0-59.
42.236 + * @param sec the seconds between 0-59.
42.237 + * @see java.util.Calendar
42.238 + * @deprecated As of JDK version 1.1,
42.239 + * replaced by <code>Calendar.set(year + 1900, month, date,
42.240 + * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
42.241 + * month, date, hrs, min, sec)</code>.
42.242 + */
42.243 + @Deprecated
42.244 + public Date(int year, int month, int date, int hrs, int min, int sec) {
42.245 + int y = year + 1900;
42.246 + // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
42.247 + if (month >= 12) {
42.248 + y += month / 12;
42.249 + month %= 12;
42.250 + } else if (month < 0) {
42.251 + y += CalendarUtils.floorDivide(month, 12);
42.252 + month = CalendarUtils.mod(month, 12);
42.253 + }
42.254 + BaseCalendar cal = getCalendarSystem(y);
42.255 + cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
42.256 + cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
42.257 + getTimeImpl();
42.258 + cdate = null;
42.259 + }
42.260 +
42.261 + /**
42.262 + * Allocates a <code>Date</code> object and initializes it so that
42.263 + * it represents the date and time indicated by the string
42.264 + * <code>s</code>, which is interpreted as if by the
42.265 + * {@link Date#parse} method.
42.266 + *
42.267 + * @param s a string representation of the date.
42.268 + * @see java.text.DateFormat
42.269 + * @see java.util.Date#parse(java.lang.String)
42.270 + * @deprecated As of JDK version 1.1,
42.271 + * replaced by <code>DateFormat.parse(String s)</code>.
42.272 + */
42.273 + @Deprecated
42.274 + public Date(String s) {
42.275 + this(parse(s));
42.276 + }
42.277 +
42.278 + /**
42.279 + * Return a copy of this object.
42.280 + */
42.281 + public Object clone() {
42.282 + Date d = null;
42.283 + try {
42.284 + d = (Date)super.clone();
42.285 + if (cdate != null) {
42.286 + d.cdate = (BaseCalendar.Date) cdate.clone();
42.287 + }
42.288 + } catch (CloneNotSupportedException e) {} // Won't happen
42.289 + return d;
42.290 + }
42.291 +
42.292 + /**
42.293 + * Determines the date and time based on the arguments. The
42.294 + * arguments are interpreted as a year, month, day of the month,
42.295 + * hour of the day, minute within the hour, and second within the
42.296 + * minute, exactly as for the <tt>Date</tt> constructor with six
42.297 + * arguments, except that the arguments are interpreted relative
42.298 + * to UTC rather than to the local time zone. The time indicated is
42.299 + * returned represented as the distance, measured in milliseconds,
42.300 + * of that time from the epoch (00:00:00 GMT on January 1, 1970).
42.301 + *
42.302 + * @param year the year minus 1900.
42.303 + * @param month the month between 0-11.
42.304 + * @param date the day of the month between 1-31.
42.305 + * @param hrs the hours between 0-23.
42.306 + * @param min the minutes between 0-59.
42.307 + * @param sec the seconds between 0-59.
42.308 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT for
42.309 + * the date and time specified by the arguments.
42.310 + * @see java.util.Calendar
42.311 + * @deprecated As of JDK version 1.1,
42.312 + * replaced by <code>Calendar.set(year + 1900, month, date,
42.313 + * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
42.314 + * month, date, hrs, min, sec)</code>, using a UTC
42.315 + * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
42.316 + */
42.317 + @Deprecated
42.318 + public static long UTC(int year, int month, int date,
42.319 + int hrs, int min, int sec) {
42.320 + int y = year + 1900;
42.321 + // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
42.322 + if (month >= 12) {
42.323 + y += month / 12;
42.324 + month %= 12;
42.325 + } else if (month < 0) {
42.326 + y += CalendarUtils.floorDivide(month, 12);
42.327 + month = CalendarUtils.mod(month, 12);
42.328 + }
42.329 + int m = month + 1;
42.330 + BaseCalendar cal = getCalendarSystem(y);
42.331 + BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
42.332 + udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
42.333 +
42.334 + // Use a Date instance to perform normalization. Its fastTime
42.335 + // is the UTC value after the normalization.
42.336 + Date d = new Date(0);
42.337 + d.normalize(udate);
42.338 + return d.fastTime;
42.339 + }
42.340 +
42.341 + /**
42.342 + * Attempts to interpret the string <tt>s</tt> as a representation
42.343 + * of a date and time. If the attempt is successful, the time
42.344 + * indicated is returned represented as the distance, measured in
42.345 + * milliseconds, of that time from the epoch (00:00:00 GMT on
42.346 + * January 1, 1970). If the attempt fails, an
42.347 + * <tt>IllegalArgumentException</tt> is thrown.
42.348 + * <p>
42.349 + * It accepts many syntaxes; in particular, it recognizes the IETF
42.350 + * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
42.351 + * understands the continental U.S. time-zone abbreviations, but for
42.352 + * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
42.353 + * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
42.354 + * meridian). If no time zone is specified, the local time zone is
42.355 + * assumed. GMT and UTC are considered equivalent.
42.356 + * <p>
42.357 + * The string <tt>s</tt> is processed from left to right, looking for
42.358 + * data of interest. Any material in <tt>s</tt> that is within the
42.359 + * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
42.360 + * Parentheses may be nested. Otherwise, the only characters permitted
42.361 + * within <tt>s</tt> are these ASCII characters:
42.362 + * <blockquote><pre>
42.363 + * abcdefghijklmnopqrstuvwxyz
42.364 + * ABCDEFGHIJKLMNOPQRSTUVWXYZ
42.365 + * 0123456789,+-:/</pre></blockquote>
42.366 + * and whitespace characters.<p>
42.367 + * A consecutive sequence of decimal digits is treated as a decimal
42.368 + * number:<ul>
42.369 + * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
42.370 + * has already been recognized, then the number is a time-zone
42.371 + * offset. If the number is less than 24, it is an offset measured
42.372 + * in hours. Otherwise, it is regarded as an offset in minutes,
42.373 + * expressed in 24-hour time format without punctuation. A
42.374 + * preceding <tt>-</tt> means a westward offset. Time zone offsets
42.375 + * are always relative to UTC (Greenwich). Thus, for example,
42.376 + * <tt>-5</tt> occurring in the string would mean "five hours west
42.377 + * of Greenwich" and <tt>+0430</tt> would mean "four hours and
42.378 + * thirty minutes east of Greenwich." It is permitted for the
42.379 + * string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
42.380 + * redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
42.381 + * <li>The number is regarded as a year number if one of the
42.382 + * following conditions is true:
42.383 + * <ul>
42.384 + * <li>The number is equal to or greater than 70 and followed by a
42.385 + * space, comma, slash, or end of string
42.386 + * <li>The number is less than 70, and both a month and a day of
42.387 + * the month have already been recognized</li>
42.388 + * </ul>
42.389 + * If the recognized year number is less than 100, it is
42.390 + * interpreted as an abbreviated year relative to a century of
42.391 + * which dates are within 80 years before and 19 years after
42.392 + * the time when the Date class is initialized.
42.393 + * After adjusting the year number, 1900 is subtracted from
42.394 + * it. For example, if the current year is 1999 then years in
42.395 + * the range 19 to 99 are assumed to mean 1919 to 1999, while
42.396 + * years from 0 to 18 are assumed to mean 2000 to 2018. Note
42.397 + * that this is slightly different from the interpretation of
42.398 + * years less than 100 that is used in {@link java.text.SimpleDateFormat}.
42.399 + * <li>If the number is followed by a colon, it is regarded as an hour,
42.400 + * unless an hour has already been recognized, in which case it is
42.401 + * regarded as a minute.
42.402 + * <li>If the number is followed by a slash, it is regarded as a month
42.403 + * (it is decreased by 1 to produce a number in the range <tt>0</tt>
42.404 + * to <tt>11</tt>), unless a month has already been recognized, in
42.405 + * which case it is regarded as a day of the month.
42.406 + * <li>If the number is followed by whitespace, a comma, a hyphen, or
42.407 + * end of string, then if an hour has been recognized but not a
42.408 + * minute, it is regarded as a minute; otherwise, if a minute has
42.409 + * been recognized but not a second, it is regarded as a second;
42.410 + * otherwise, it is regarded as a day of the month. </ul><p>
42.411 + * A consecutive sequence of letters is regarded as a word and treated
42.412 + * as follows:<ul>
42.413 + * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
42.414 + * the parse fails if an hour has not been recognized or is less
42.415 + * than <tt>1</tt> or greater than <tt>12</tt>).
42.416 + * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
42.417 + * to the hour (but the parse fails if an hour has not been
42.418 + * recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
42.419 + * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
42.420 + * WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
42.421 + * case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
42.422 + * <tt>Thurs</tt> are ignored.
42.423 + * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
42.424 + * FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
42.425 + * OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
42.426 + * considering them in the order given here, is recognized as
42.427 + * specifying a month and is converted to a number (<tt>0</tt> to
42.428 + * <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
42.429 + * <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
42.430 + * is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
42.431 + * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
42.432 + * case, is treated as referring to UTC.
42.433 + * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
42.434 + * ignoring case, is recognized as referring to the time zone in
42.435 + * North America that is five, six, seven, or eight hours west of
42.436 + * Greenwich, respectively. Any word that matches <tt>EDT, CDT,
42.437 + * MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
42.438 + * referring to the same time zone, respectively, during daylight
42.439 + * saving time.</ul><p>
42.440 + * Once the entire string s has been scanned, it is converted to a time
42.441 + * result in one of two ways. If a time zone or time-zone offset has been
42.442 + * recognized, then the year, month, day of month, hour, minute, and
42.443 + * second are interpreted in UTC and then the time-zone offset is
42.444 + * applied. Otherwise, the year, month, day of month, hour, minute, and
42.445 + * second are interpreted in the local time zone.
42.446 + *
42.447 + * @param s a string to be parsed as a date.
42.448 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
42.449 + * represented by the string argument.
42.450 + * @see java.text.DateFormat
42.451 + * @deprecated As of JDK version 1.1,
42.452 + * replaced by <code>DateFormat.parse(String s)</code>.
42.453 + */
42.454 + @Deprecated
42.455 + public static long parse(String s) {
42.456 + int year = Integer.MIN_VALUE;
42.457 + int mon = -1;
42.458 + int mday = -1;
42.459 + int hour = -1;
42.460 + int min = -1;
42.461 + int sec = -1;
42.462 + int millis = -1;
42.463 + int c = -1;
42.464 + int i = 0;
42.465 + int n = -1;
42.466 + int wst = -1;
42.467 + int tzoffset = -1;
42.468 + int prevc = 0;
42.469 + syntax:
42.470 + {
42.471 + if (s == null)
42.472 + break syntax;
42.473 + int limit = s.length();
42.474 + while (i < limit) {
42.475 + c = s.charAt(i);
42.476 + i++;
42.477 + if (c <= ' ' || c == ',')
42.478 + continue;
42.479 + if (c == '(') { // skip comments
42.480 + int depth = 1;
42.481 + while (i < limit) {
42.482 + c = s.charAt(i);
42.483 + i++;
42.484 + if (c == '(') depth++;
42.485 + else if (c == ')')
42.486 + if (--depth <= 0)
42.487 + break;
42.488 + }
42.489 + continue;
42.490 + }
42.491 + if ('0' <= c && c <= '9') {
42.492 + n = c - '0';
42.493 + while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
42.494 + n = n * 10 + c - '0';
42.495 + i++;
42.496 + }
42.497 + if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
42.498 + // timezone offset
42.499 + if (n < 24)
42.500 + n = n * 60; // EG. "GMT-3"
42.501 + else
42.502 + n = n % 100 + n / 100 * 60; // eg "GMT-0430"
42.503 + if (prevc == '+') // plus means east of GMT
42.504 + n = -n;
42.505 + if (tzoffset != 0 && tzoffset != -1)
42.506 + break syntax;
42.507 + tzoffset = n;
42.508 + } else if (n >= 70)
42.509 + if (year != Integer.MIN_VALUE)
42.510 + break syntax;
42.511 + else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
42.512 + // year = n < 1900 ? n : n - 1900;
42.513 + year = n;
42.514 + else
42.515 + break syntax;
42.516 + else if (c == ':')
42.517 + if (hour < 0)
42.518 + hour = (byte) n;
42.519 + else if (min < 0)
42.520 + min = (byte) n;
42.521 + else
42.522 + break syntax;
42.523 + else if (c == '/')
42.524 + if (mon < 0)
42.525 + mon = (byte) (n - 1);
42.526 + else if (mday < 0)
42.527 + mday = (byte) n;
42.528 + else
42.529 + break syntax;
42.530 + else if (i < limit && c != ',' && c > ' ' && c != '-')
42.531 + break syntax;
42.532 + else if (hour >= 0 && min < 0)
42.533 + min = (byte) n;
42.534 + else if (min >= 0 && sec < 0)
42.535 + sec = (byte) n;
42.536 + else if (mday < 0)
42.537 + mday = (byte) n;
42.538 + // Handle two-digit years < 70 (70-99 handled above).
42.539 + else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
42.540 + year = n;
42.541 + else
42.542 + break syntax;
42.543 + prevc = 0;
42.544 + } else if (c == '/' || c == ':' || c == '+' || c == '-')
42.545 + prevc = c;
42.546 + else {
42.547 + int st = i - 1;
42.548 + while (i < limit) {
42.549 + c = s.charAt(i);
42.550 + if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
42.551 + break;
42.552 + i++;
42.553 + }
42.554 + if (i <= st + 1)
42.555 + break syntax;
42.556 + int k;
42.557 + for (k = wtb.length; --k >= 0;)
42.558 + if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
42.559 + int action = ttb[k];
42.560 + if (action != 0) {
42.561 + if (action == 1) { // pm
42.562 + if (hour > 12 || hour < 1)
42.563 + break syntax;
42.564 + else if (hour < 12)
42.565 + hour += 12;
42.566 + } else if (action == 14) { // am
42.567 + if (hour > 12 || hour < 1)
42.568 + break syntax;
42.569 + else if (hour == 12)
42.570 + hour = 0;
42.571 + } else if (action <= 13) { // month!
42.572 + if (mon < 0)
42.573 + mon = (byte) (action - 2);
42.574 + else
42.575 + break syntax;
42.576 + } else {
42.577 + tzoffset = action - 10000;
42.578 + }
42.579 + }
42.580 + break;
42.581 + }
42.582 + if (k < 0)
42.583 + break syntax;
42.584 + prevc = 0;
42.585 + }
42.586 + }
42.587 + if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
42.588 + break syntax;
42.589 + // Parse 2-digit years within the correct default century.
42.590 + if (year < 100) {
42.591 + synchronized (Date.class) {
42.592 + if (defaultCenturyStart == 0) {
42.593 + defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
42.594 + }
42.595 + }
42.596 + year += (defaultCenturyStart / 100) * 100;
42.597 + if (year < defaultCenturyStart) year += 100;
42.598 + }
42.599 + if (sec < 0)
42.600 + sec = 0;
42.601 + if (min < 0)
42.602 + min = 0;
42.603 + if (hour < 0)
42.604 + hour = 0;
42.605 + BaseCalendar cal = getCalendarSystem(year);
42.606 + if (tzoffset == -1) { // no time zone specified, have to use local
42.607 + BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
42.608 + ldate.setDate(year, mon + 1, mday);
42.609 + ldate.setTimeOfDay(hour, min, sec, 0);
42.610 + return cal.getTime(ldate);
42.611 + }
42.612 + BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
42.613 + udate.setDate(year, mon + 1, mday);
42.614 + udate.setTimeOfDay(hour, min, sec, 0);
42.615 + return cal.getTime(udate) + tzoffset * (60 * 1000);
42.616 + }
42.617 + // syntax error
42.618 + throw new IllegalArgumentException();
42.619 + }
42.620 + private final static String wtb[] = {
42.621 + "am", "pm",
42.622 + "monday", "tuesday", "wednesday", "thursday", "friday",
42.623 + "saturday", "sunday",
42.624 + "january", "february", "march", "april", "may", "june",
42.625 + "july", "august", "september", "october", "november", "december",
42.626 + "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
42.627 + "mst", "mdt", "pst", "pdt"
42.628 + };
42.629 + private final static int ttb[] = {
42.630 + 14, 1, 0, 0, 0, 0, 0, 0, 0,
42.631 + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
42.632 + 10000 + 0, 10000 + 0, 10000 + 0, // GMT/UT/UTC
42.633 + 10000 + 5 * 60, 10000 + 4 * 60, // EST/EDT
42.634 + 10000 + 6 * 60, 10000 + 5 * 60, // CST/CDT
42.635 + 10000 + 7 * 60, 10000 + 6 * 60, // MST/MDT
42.636 + 10000 + 8 * 60, 10000 + 7 * 60 // PST/PDT
42.637 + };
42.638 +
42.639 + /**
42.640 + * Returns a value that is the result of subtracting 1900 from the
42.641 + * year that contains or begins with the instant in time represented
42.642 + * by this <code>Date</code> object, as interpreted in the local
42.643 + * time zone.
42.644 + *
42.645 + * @return the year represented by this date, minus 1900.
42.646 + * @see java.util.Calendar
42.647 + * @deprecated As of JDK version 1.1,
42.648 + * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
42.649 + */
42.650 + @Deprecated
42.651 + public int getYear() {
42.652 + return normalize().getYear() - 1900;
42.653 + }
42.654 +
42.655 + /**
42.656 + * Sets the year of this <tt>Date</tt> object to be the specified
42.657 + * value plus 1900. This <code>Date</code> object is modified so
42.658 + * that it represents a point in time within the specified year,
42.659 + * with the month, date, hour, minute, and second the same as
42.660 + * before, as interpreted in the local time zone. (Of course, if
42.661 + * the date was February 29, for example, and the year is set to a
42.662 + * non-leap year, then the new date will be treated as if it were
42.663 + * on March 1.)
42.664 + *
42.665 + * @param year the year value.
42.666 + * @see java.util.Calendar
42.667 + * @deprecated As of JDK version 1.1,
42.668 + * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
42.669 + */
42.670 + @Deprecated
42.671 + public void setYear(int year) {
42.672 + getCalendarDate().setNormalizedYear(year + 1900);
42.673 + }
42.674 +
42.675 + /**
42.676 + * Returns a number representing the month that contains or begins
42.677 + * with the instant in time represented by this <tt>Date</tt> object.
42.678 + * The value returned is between <code>0</code> and <code>11</code>,
42.679 + * with the value <code>0</code> representing January.
42.680 + *
42.681 + * @return the month represented by this date.
42.682 + * @see java.util.Calendar
42.683 + * @deprecated As of JDK version 1.1,
42.684 + * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
42.685 + */
42.686 + @Deprecated
42.687 + public int getMonth() {
42.688 + return normalize().getMonth() - 1; // adjust 1-based to 0-based
42.689 + }
42.690 +
42.691 + /**
42.692 + * Sets the month of this date to the specified value. This
42.693 + * <tt>Date</tt> object is modified so that it represents a point
42.694 + * in time within the specified month, with the year, date, hour,
42.695 + * minute, and second the same as before, as interpreted in the
42.696 + * local time zone. If the date was October 31, for example, and
42.697 + * the month is set to June, then the new date will be treated as
42.698 + * if it were on July 1, because June has only 30 days.
42.699 + *
42.700 + * @param month the month value between 0-11.
42.701 + * @see java.util.Calendar
42.702 + * @deprecated As of JDK version 1.1,
42.703 + * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
42.704 + */
42.705 + @Deprecated
42.706 + public void setMonth(int month) {
42.707 + int y = 0;
42.708 + if (month >= 12) {
42.709 + y = month / 12;
42.710 + month %= 12;
42.711 + } else if (month < 0) {
42.712 + y = CalendarUtils.floorDivide(month, 12);
42.713 + month = CalendarUtils.mod(month, 12);
42.714 + }
42.715 + BaseCalendar.Date d = getCalendarDate();
42.716 + if (y != 0) {
42.717 + d.setNormalizedYear(d.getNormalizedYear() + y);
42.718 + }
42.719 + d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
42.720 + }
42.721 +
42.722 + /**
42.723 + * Returns the day of the month represented by this <tt>Date</tt> object.
42.724 + * The value returned is between <code>1</code> and <code>31</code>
42.725 + * representing the day of the month that contains or begins with the
42.726 + * instant in time represented by this <tt>Date</tt> object, as
42.727 + * interpreted in the local time zone.
42.728 + *
42.729 + * @return the day of the month represented by this date.
42.730 + * @see java.util.Calendar
42.731 + * @deprecated As of JDK version 1.1,
42.732 + * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
42.733 + * @deprecated
42.734 + */
42.735 + @Deprecated
42.736 + public int getDate() {
42.737 + return normalize().getDayOfMonth();
42.738 + }
42.739 +
42.740 + /**
42.741 + * Sets the day of the month of this <tt>Date</tt> object to the
42.742 + * specified value. This <tt>Date</tt> object is modified so that
42.743 + * it represents a point in time within the specified day of the
42.744 + * month, with the year, month, hour, minute, and second the same
42.745 + * as before, as interpreted in the local time zone. If the date
42.746 + * was April 30, for example, and the date is set to 31, then it
42.747 + * will be treated as if it were on May 1, because April has only
42.748 + * 30 days.
42.749 + *
42.750 + * @param date the day of the month value between 1-31.
42.751 + * @see java.util.Calendar
42.752 + * @deprecated As of JDK version 1.1,
42.753 + * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
42.754 + */
42.755 + @Deprecated
42.756 + public void setDate(int date) {
42.757 + getCalendarDate().setDayOfMonth(date);
42.758 + }
42.759 +
42.760 + /**
42.761 + * Returns the day of the week represented by this date. The
42.762 + * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
42.763 + * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
42.764 + * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
42.765 + * represents the day of the week that contains or begins with
42.766 + * the instant in time represented by this <tt>Date</tt> object,
42.767 + * as interpreted in the local time zone.
42.768 + *
42.769 + * @return the day of the week represented by this date.
42.770 + * @see java.util.Calendar
42.771 + * @deprecated As of JDK version 1.1,
42.772 + * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
42.773 + */
42.774 + @Deprecated
42.775 + public int getDay() {
42.776 + return normalize().getDayOfWeek() - gcal.SUNDAY;
42.777 + }
42.778 +
42.779 + /**
42.780 + * Returns the hour represented by this <tt>Date</tt> object. The
42.781 + * returned value is a number (<tt>0</tt> through <tt>23</tt>)
42.782 + * representing the hour within the day that contains or begins
42.783 + * with the instant in time represented by this <tt>Date</tt>
42.784 + * object, as interpreted in the local time zone.
42.785 + *
42.786 + * @return the hour represented by this date.
42.787 + * @see java.util.Calendar
42.788 + * @deprecated As of JDK version 1.1,
42.789 + * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
42.790 + */
42.791 + @Deprecated
42.792 + public int getHours() {
42.793 + return normalize().getHours();
42.794 + }
42.795 +
42.796 + /**
42.797 + * Sets the hour of this <tt>Date</tt> object to the specified value.
42.798 + * This <tt>Date</tt> object is modified so that it represents a point
42.799 + * in time within the specified hour of the day, with the year, month,
42.800 + * date, minute, and second the same as before, as interpreted in the
42.801 + * local time zone.
42.802 + *
42.803 + * @param hours the hour value.
42.804 + * @see java.util.Calendar
42.805 + * @deprecated As of JDK version 1.1,
42.806 + * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
42.807 + */
42.808 + @Deprecated
42.809 + public void setHours(int hours) {
42.810 + getCalendarDate().setHours(hours);
42.811 + }
42.812 +
42.813 + /**
42.814 + * Returns the number of minutes past the hour represented by this date,
42.815 + * as interpreted in the local time zone.
42.816 + * The value returned is between <code>0</code> and <code>59</code>.
42.817 + *
42.818 + * @return the number of minutes past the hour represented by this date.
42.819 + * @see java.util.Calendar
42.820 + * @deprecated As of JDK version 1.1,
42.821 + * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
42.822 + */
42.823 + @Deprecated
42.824 + public int getMinutes() {
42.825 + return normalize().getMinutes();
42.826 + }
42.827 +
42.828 + /**
42.829 + * Sets the minutes of this <tt>Date</tt> object to the specified value.
42.830 + * This <tt>Date</tt> object is modified so that it represents a point
42.831 + * in time within the specified minute of the hour, with the year, month,
42.832 + * date, hour, and second the same as before, as interpreted in the
42.833 + * local time zone.
42.834 + *
42.835 + * @param minutes the value of the minutes.
42.836 + * @see java.util.Calendar
42.837 + * @deprecated As of JDK version 1.1,
42.838 + * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
42.839 + */
42.840 + @Deprecated
42.841 + public void setMinutes(int minutes) {
42.842 + getCalendarDate().setMinutes(minutes);
42.843 + }
42.844 +
42.845 + /**
42.846 + * Returns the number of seconds past the minute represented by this date.
42.847 + * The value returned is between <code>0</code> and <code>61</code>. The
42.848 + * values <code>60</code> and <code>61</code> can only occur on those
42.849 + * Java Virtual Machines that take leap seconds into account.
42.850 + *
42.851 + * @return the number of seconds past the minute represented by this date.
42.852 + * @see java.util.Calendar
42.853 + * @deprecated As of JDK version 1.1,
42.854 + * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
42.855 + */
42.856 + @Deprecated
42.857 + public int getSeconds() {
42.858 + return normalize().getSeconds();
42.859 + }
42.860 +
42.861 + /**
42.862 + * Sets the seconds of this <tt>Date</tt> to the specified value.
42.863 + * This <tt>Date</tt> object is modified so that it represents a
42.864 + * point in time within the specified second of the minute, with
42.865 + * the year, month, date, hour, and minute the same as before, as
42.866 + * interpreted in the local time zone.
42.867 + *
42.868 + * @param seconds the seconds value.
42.869 + * @see java.util.Calendar
42.870 + * @deprecated As of JDK version 1.1,
42.871 + * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
42.872 + */
42.873 + @Deprecated
42.874 + public void setSeconds(int seconds) {
42.875 + getCalendarDate().setSeconds(seconds);
42.876 + }
42.877 +
42.878 + /**
42.879 + * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
42.880 + * represented by this <tt>Date</tt> object.
42.881 + *
42.882 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
42.883 + * represented by this date.
42.884 + */
42.885 + public long getTime() {
42.886 + return getTimeImpl();
42.887 + }
42.888 +
42.889 + private final long getTimeImpl() {
42.890 + if (cdate != null && !cdate.isNormalized()) {
42.891 + normalize();
42.892 + }
42.893 + return fastTime;
42.894 + }
42.895 +
42.896 + /**
42.897 + * Sets this <code>Date</code> object to represent a point in time that is
42.898 + * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
42.899 + *
42.900 + * @param time the number of milliseconds.
42.901 + */
42.902 + public void setTime(long time) {
42.903 + fastTime = time;
42.904 + cdate = null;
42.905 + }
42.906 +
42.907 + /**
42.908 + * Tests if this date is before the specified date.
42.909 + *
42.910 + * @param when a date.
42.911 + * @return <code>true</code> if and only if the instant of time
42.912 + * represented by this <tt>Date</tt> object is strictly
42.913 + * earlier than the instant represented by <tt>when</tt>;
42.914 + * <code>false</code> otherwise.
42.915 + * @exception NullPointerException if <code>when</code> is null.
42.916 + */
42.917 + public boolean before(Date when) {
42.918 + return getMillisOf(this) < getMillisOf(when);
42.919 + }
42.920 +
42.921 + /**
42.922 + * Tests if this date is after the specified date.
42.923 + *
42.924 + * @param when a date.
42.925 + * @return <code>true</code> if and only if the instant represented
42.926 + * by this <tt>Date</tt> object is strictly later than the
42.927 + * instant represented by <tt>when</tt>;
42.928 + * <code>false</code> otherwise.
42.929 + * @exception NullPointerException if <code>when</code> is null.
42.930 + */
42.931 + public boolean after(Date when) {
42.932 + return getMillisOf(this) > getMillisOf(when);
42.933 + }
42.934 +
42.935 + /**
42.936 + * Compares two dates for equality.
42.937 + * The result is <code>true</code> if and only if the argument is
42.938 + * not <code>null</code> and is a <code>Date</code> object that
42.939 + * represents the same point in time, to the millisecond, as this object.
42.940 + * <p>
42.941 + * Thus, two <code>Date</code> objects are equal if and only if the
42.942 + * <code>getTime</code> method returns the same <code>long</code>
42.943 + * value for both.
42.944 + *
42.945 + * @param obj the object to compare with.
42.946 + * @return <code>true</code> if the objects are the same;
42.947 + * <code>false</code> otherwise.
42.948 + * @see java.util.Date#getTime()
42.949 + */
42.950 + public boolean equals(Object obj) {
42.951 + return obj instanceof Date && getTime() == ((Date) obj).getTime();
42.952 + }
42.953 +
42.954 + /**
42.955 + * Returns the millisecond value of this <code>Date</code> object
42.956 + * without affecting its internal state.
42.957 + */
42.958 + static final long getMillisOf(Date date) {
42.959 + if (date.cdate == null || date.cdate.isNormalized()) {
42.960 + return date.fastTime;
42.961 + }
42.962 + BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
42.963 + return gcal.getTime(d);
42.964 + }
42.965 +
42.966 + /**
42.967 + * Compares two Dates for ordering.
42.968 + *
42.969 + * @param anotherDate the <code>Date</code> to be compared.
42.970 + * @return the value <code>0</code> if the argument Date is equal to
42.971 + * this Date; a value less than <code>0</code> if this Date
42.972 + * is before the Date argument; and a value greater than
42.973 + * <code>0</code> if this Date is after the Date argument.
42.974 + * @since 1.2
42.975 + * @exception NullPointerException if <code>anotherDate</code> is null.
42.976 + */
42.977 + public int compareTo(Date anotherDate) {
42.978 + long thisTime = getMillisOf(this);
42.979 + long anotherTime = getMillisOf(anotherDate);
42.980 + return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
42.981 + }
42.982 +
42.983 + /**
42.984 + * Returns a hash code value for this object. The result is the
42.985 + * exclusive OR of the two halves of the primitive <tt>long</tt>
42.986 + * value returned by the {@link Date#getTime}
42.987 + * method. That is, the hash code is the value of the expression:
42.988 + * <blockquote><pre>
42.989 + * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
42.990 + *
42.991 + * @return a hash code value for this object.
42.992 + */
42.993 + public int hashCode() {
42.994 + long ht = this.getTime();
42.995 + return (int) ht ^ (int) (ht >> 32);
42.996 + }
42.997 +
42.998 + /**
42.999 + * Converts this <code>Date</code> object to a <code>String</code>
42.1000 + * of the form:
42.1001 + * <blockquote><pre>
42.1002 + * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
42.1003 + * where:<ul>
42.1004 + * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
42.1005 + * Thu, Fri, Sat</tt>).
42.1006 + * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
42.1007 + * Jul, Aug, Sep, Oct, Nov, Dec</tt>).
42.1008 + * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
42.1009 + * <tt>31</tt>), as two decimal digits.
42.1010 + * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
42.1011 + * <tt>23</tt>), as two decimal digits.
42.1012 + * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
42.1013 + * <tt>59</tt>), as two decimal digits.
42.1014 + * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
42.1015 + * <tt>61</tt>, as two decimal digits.
42.1016 + * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
42.1017 + * time). Standard time zone abbreviations include those
42.1018 + * recognized by the method <tt>parse</tt>. If time zone
42.1019 + * information is not available, then <tt>zzz</tt> is empty -
42.1020 + * that is, it consists of no characters at all.
42.1021 + * <li><tt>yyyy</tt> is the year, as four decimal digits.
42.1022 + * </ul>
42.1023 + *
42.1024 + * @return a string representation of this date.
42.1025 + * @see java.util.Date#toLocaleString()
42.1026 + * @see java.util.Date#toGMTString()
42.1027 + */
42.1028 + public String toString() {
42.1029 + // "EEE MMM dd HH:mm:ss zzz yyyy";
42.1030 + BaseCalendar.Date date = normalize();
42.1031 + StringBuilder sb = new StringBuilder(28);
42.1032 + int index = date.getDayOfWeek();
42.1033 + if (index == gcal.SUNDAY) {
42.1034 + index = 8;
42.1035 + }
42.1036 + convertToAbbr(sb, wtb[index]).append(' '); // EEE
42.1037 + convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
42.1038 + CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
42.1039 +
42.1040 + CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
42.1041 + CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
42.1042 + CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
42.1043 + TimeZone zi = date.getZone();
42.1044 + if (zi != null) {
42.1045 + sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
42.1046 + } else {
42.1047 + sb.append("GMT");
42.1048 + }
42.1049 + sb.append(' ').append(date.getYear()); // yyyy
42.1050 + return sb.toString();
42.1051 + }
42.1052 +
42.1053 + /**
42.1054 + * Converts the given name to its 3-letter abbreviation (e.g.,
42.1055 + * "monday" -> "Mon") and stored the abbreviation in the given
42.1056 + * <code>StringBuilder</code>.
42.1057 + */
42.1058 + private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
42.1059 + sb.append(Character.toUpperCase(name.charAt(0)));
42.1060 + sb.append(name.charAt(1)).append(name.charAt(2));
42.1061 + return sb;
42.1062 + }
42.1063 +
42.1064 + /**
42.1065 + * Creates a string representation of this <tt>Date</tt> object in an
42.1066 + * implementation-dependent form. The intent is that the form should
42.1067 + * be familiar to the user of the Java application, wherever it may
42.1068 + * happen to be running. The intent is comparable to that of the
42.1069 + * "<code>%c</code>" format supported by the <code>strftime()</code>
42.1070 + * function of ISO C.
42.1071 + *
42.1072 + * @return a string representation of this date, using the locale
42.1073 + * conventions.
42.1074 + * @see java.text.DateFormat
42.1075 + * @see java.util.Date#toString()
42.1076 + * @see java.util.Date#toGMTString()
42.1077 + * @deprecated As of JDK version 1.1,
42.1078 + * replaced by <code>DateFormat.format(Date date)</code>.
42.1079 + */
42.1080 + @Deprecated
42.1081 + public String toLocaleString() {
42.1082 + DateFormat formatter = DateFormat.getDateTimeInstance();
42.1083 + return formatter.format(this);
42.1084 + }
42.1085 +
42.1086 + /**
42.1087 + * Creates a string representation of this <tt>Date</tt> object of
42.1088 + * the form:
42.1089 + * <blockquote<pre>
42.1090 + * d mon yyyy hh:mm:ss GMT</pre></blockquote>
42.1091 + * where:<ul>
42.1092 + * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
42.1093 + * as one or two decimal digits.
42.1094 + * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
42.1095 + * Aug, Sep, Oct, Nov, Dec</tt>).
42.1096 + * <li><i>yyyy</i> is the year, as four decimal digits.
42.1097 + * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
42.1098 + * as two decimal digits.
42.1099 + * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
42.1100 + * <tt>59</tt>), as two decimal digits.
42.1101 + * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
42.1102 + * <tt>61</tt>), as two decimal digits.
42.1103 + * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
42.1104 + * Greenwich Mean Time.
42.1105 + * </ul><p>
42.1106 + * The result does not depend on the local time zone.
42.1107 + *
42.1108 + * @return a string representation of this date, using the Internet GMT
42.1109 + * conventions.
42.1110 + * @see java.text.DateFormat
42.1111 + * @see java.util.Date#toString()
42.1112 + * @see java.util.Date#toLocaleString()
42.1113 + * @deprecated As of JDK version 1.1,
42.1114 + * replaced by <code>DateFormat.format(Date date)</code>, using a
42.1115 + * GMT <code>TimeZone</code>.
42.1116 + */
42.1117 + @Deprecated
42.1118 + public String toGMTString() {
42.1119 + // d MMM yyyy HH:mm:ss 'GMT'
42.1120 + long t = getTime();
42.1121 + BaseCalendar cal = getCalendarSystem(t);
42.1122 + BaseCalendar.Date date =
42.1123 + (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
42.1124 + StringBuilder sb = new StringBuilder(32);
42.1125 + CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
42.1126 + convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
42.1127 + sb.append(date.getYear()).append(' '); // yyyy
42.1128 + CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
42.1129 + CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
42.1130 + CalendarUtils.sprintf0d(sb, date.getSeconds(), 2); // ss
42.1131 + sb.append(" GMT"); // ' GMT'
42.1132 + return sb.toString();
42.1133 + }
42.1134 +
42.1135 + /**
42.1136 + * Returns the offset, measured in minutes, for the local time zone
42.1137 + * relative to UTC that is appropriate for the time represented by
42.1138 + * this <code>Date</code> object.
42.1139 + * <p>
42.1140 + * For example, in Massachusetts, five time zones west of Greenwich:
42.1141 + * <blockquote><pre>
42.1142 + * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
42.1143 + * because on February 14, 1996, standard time (Eastern Standard Time)
42.1144 + * is in use, which is offset five hours from UTC; but:
42.1145 + * <blockquote><pre>
42.1146 + * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
42.1147 + * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
42.1148 + * is in use, which is offset only four hours from UTC.<p>
42.1149 + * This method produces the same result as if it computed:
42.1150 + * <blockquote><pre>
42.1151 + * (this.getTime() - UTC(this.getYear(),
42.1152 + * this.getMonth(),
42.1153 + * this.getDate(),
42.1154 + * this.getHours(),
42.1155 + * this.getMinutes(),
42.1156 + * this.getSeconds())) / (60 * 1000)
42.1157 + * </pre></blockquote>
42.1158 + *
42.1159 + * @return the time-zone offset, in minutes, for the current time zone.
42.1160 + * @see java.util.Calendar#ZONE_OFFSET
42.1161 + * @see java.util.Calendar#DST_OFFSET
42.1162 + * @see java.util.TimeZone#getDefault
42.1163 + * @deprecated As of JDK version 1.1,
42.1164 + * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
42.1165 + * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
42.1166 + */
42.1167 + @Deprecated
42.1168 + public int getTimezoneOffset() {
42.1169 + int zoneOffset;
42.1170 + if (cdate == null) {
42.1171 + TimeZone tz = TimeZone.getDefaultRef();
42.1172 + if (tz instanceof ZoneInfo) {
42.1173 + zoneOffset = ((ZoneInfo)tz).getOffsets(fastTime, null);
42.1174 + } else {
42.1175 + zoneOffset = tz.getOffset(fastTime);
42.1176 + }
42.1177 + } else {
42.1178 + normalize();
42.1179 + zoneOffset = cdate.getZoneOffset();
42.1180 + }
42.1181 + return -zoneOffset/60000; // convert to minutes
42.1182 + }
42.1183 +
42.1184 + private final BaseCalendar.Date getCalendarDate() {
42.1185 + if (cdate == null) {
42.1186 + BaseCalendar cal = getCalendarSystem(fastTime);
42.1187 + cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
42.1188 + TimeZone.getDefaultRef());
42.1189 + }
42.1190 + return cdate;
42.1191 + }
42.1192 +
42.1193 + private final BaseCalendar.Date normalize() {
42.1194 + if (cdate == null) {
42.1195 + BaseCalendar cal = getCalendarSystem(fastTime);
42.1196 + cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
42.1197 + TimeZone.getDefaultRef());
42.1198 + return cdate;
42.1199 + }
42.1200 +
42.1201 + // Normalize cdate with the TimeZone in cdate first. This is
42.1202 + // required for the compatible behavior.
42.1203 + if (!cdate.isNormalized()) {
42.1204 + cdate = normalize(cdate);
42.1205 + }
42.1206 +
42.1207 + // If the default TimeZone has changed, then recalculate the
42.1208 + // fields with the new TimeZone.
42.1209 + TimeZone tz = TimeZone.getDefaultRef();
42.1210 + if (tz != cdate.getZone()) {
42.1211 + cdate.setZone(tz);
42.1212 + CalendarSystem cal = getCalendarSystem(cdate);
42.1213 + cal.getCalendarDate(fastTime, cdate);
42.1214 + }
42.1215 + return cdate;
42.1216 + }
42.1217 +
42.1218 + // fastTime and the returned data are in sync upon return.
42.1219 + private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
42.1220 + int y = date.getNormalizedYear();
42.1221 + int m = date.getMonth();
42.1222 + int d = date.getDayOfMonth();
42.1223 + int hh = date.getHours();
42.1224 + int mm = date.getMinutes();
42.1225 + int ss = date.getSeconds();
42.1226 + int ms = date.getMillis();
42.1227 + TimeZone tz = date.getZone();
42.1228 +
42.1229 + // If the specified year can't be handled using a long value
42.1230 + // in milliseconds, GregorianCalendar is used for full
42.1231 + // compatibility with underflow and overflow. This is required
42.1232 + // by some JCK tests. The limits are based max year values -
42.1233 + // years that can be represented by max values of d, hh, mm,
42.1234 + // ss and ms. Also, let GregorianCalendar handle the default
42.1235 + // cutover year so that we don't need to worry about the
42.1236 + // transition here.
42.1237 + if (y == 1582 || y > 280000000 || y < -280000000) {
42.1238 + if (tz == null) {
42.1239 + tz = TimeZone.getTimeZone("GMT");
42.1240 + }
42.1241 + GregorianCalendar gc = new GregorianCalendar(tz);
42.1242 + gc.clear();
42.1243 + gc.set(gc.MILLISECOND, ms);
42.1244 + gc.set(y, m-1, d, hh, mm, ss);
42.1245 + fastTime = gc.getTimeInMillis();
42.1246 + BaseCalendar cal = getCalendarSystem(fastTime);
42.1247 + date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
42.1248 + return date;
42.1249 + }
42.1250 +
42.1251 + BaseCalendar cal = getCalendarSystem(y);
42.1252 + if (cal != getCalendarSystem(date)) {
42.1253 + date = (BaseCalendar.Date) cal.newCalendarDate(tz);
42.1254 + date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
42.1255 + }
42.1256 + // Perform the GregorianCalendar-style normalization.
42.1257 + fastTime = cal.getTime(date);
42.1258 +
42.1259 + // In case the normalized date requires the other calendar
42.1260 + // system, we need to recalculate it using the other one.
42.1261 + BaseCalendar ncal = getCalendarSystem(fastTime);
42.1262 + if (ncal != cal) {
42.1263 + date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
42.1264 + date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
42.1265 + fastTime = ncal.getTime(date);
42.1266 + }
42.1267 + return date;
42.1268 + }
42.1269 +
42.1270 + /**
42.1271 + * Returns the Gregorian or Julian calendar system to use with the
42.1272 + * given date. Use Gregorian from October 15, 1582.
42.1273 + *
42.1274 + * @param year normalized calendar year (not -1900)
42.1275 + * @return the CalendarSystem to use for the specified date
42.1276 + */
42.1277 + private static final BaseCalendar getCalendarSystem(int year) {
42.1278 + if (year >= 1582) {
42.1279 + return gcal;
42.1280 + }
42.1281 + return getJulianCalendar();
42.1282 + }
42.1283 +
42.1284 + private static final BaseCalendar getCalendarSystem(long utc) {
42.1285 + // Quickly check if the time stamp given by `utc' is the Epoch
42.1286 + // or later. If it's before 1970, we convert the cutover to
42.1287 + // local time to compare.
42.1288 + if (utc >= 0
42.1289 + || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
42.1290 + - TimeZone.getDefaultRef().getOffset(utc)) {
42.1291 + return gcal;
42.1292 + }
42.1293 + return getJulianCalendar();
42.1294 + }
42.1295 +
42.1296 + private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
42.1297 + if (jcal == null) {
42.1298 + return gcal;
42.1299 + }
42.1300 + if (cdate.getEra() != null) {
42.1301 + return jcal;
42.1302 + }
42.1303 + return gcal;
42.1304 + }
42.1305 +
42.1306 + synchronized private static final BaseCalendar getJulianCalendar() {
42.1307 + if (jcal == null) {
42.1308 + jcal = (BaseCalendar) CalendarSystem.forName("julian");
42.1309 + }
42.1310 + return jcal;
42.1311 + }
42.1312 +
42.1313 + /**
42.1314 + * Save the state of this object to a stream (i.e., serialize it).
42.1315 + *
42.1316 + * @serialData The value returned by <code>getTime()</code>
42.1317 + * is emitted (long). This represents the offset from
42.1318 + * January 1, 1970, 00:00:00 GMT in milliseconds.
42.1319 + */
42.1320 + private void writeObject(ObjectOutputStream s)
42.1321 + throws IOException
42.1322 + {
42.1323 + s.writeLong(getTimeImpl());
42.1324 + }
42.1325 +
42.1326 + /**
42.1327 + * Reconstitute this object from a stream (i.e., deserialize it).
42.1328 + */
42.1329 + private void readObject(ObjectInputStream s)
42.1330 + throws IOException, ClassNotFoundException
42.1331 + {
42.1332 + fastTime = s.readLong();
42.1333 + }
42.1334 +}
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/rt/emul/compact/src/main/java/java/util/MissingResourceException.java Thu Oct 03 15:40:35 2013 +0200
43.3 @@ -0,0 +1,124 @@
43.4 +/*
43.5 + * Copyright (c) 1996, 2005, 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 +/*
43.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
43.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
43.32 + *
43.33 + * The original version of this source code and documentation
43.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
43.35 + * subsidiary of IBM. These materials are provided under terms
43.36 + * of a License Agreement between Taligent and Sun. This technology
43.37 + * is protected by multiple US and International patents.
43.38 + *
43.39 + * This notice and attribution to Taligent may not be removed.
43.40 + * Taligent is a registered trademark of Taligent, Inc.
43.41 + *
43.42 + */
43.43 +
43.44 +package java.util;
43.45 +
43.46 +/**
43.47 + * Signals that a resource is missing.
43.48 + * @see java.lang.Exception
43.49 + * @see ResourceBundle
43.50 + * @author Mark Davis
43.51 + * @since JDK1.1
43.52 + */
43.53 +public
43.54 +class MissingResourceException extends RuntimeException {
43.55 +
43.56 + /**
43.57 + * Constructs a MissingResourceException with the specified information.
43.58 + * A detail message is a String that describes this particular exception.
43.59 + * @param s the detail message
43.60 + * @param className the name of the resource class
43.61 + * @param key the key for the missing resource.
43.62 + */
43.63 + public MissingResourceException(String s, String className, String key) {
43.64 + super(s);
43.65 + this.className = className;
43.66 + this.key = key;
43.67 + }
43.68 +
43.69 + /**
43.70 + * Constructs a <code>MissingResourceException</code> with
43.71 + * <code>message</code>, <code>className</code>, <code>key</code>,
43.72 + * and <code>cause</code>. This constructor is package private for
43.73 + * use by <code>ResourceBundle.getBundle</code>.
43.74 + *
43.75 + * @param message
43.76 + * the detail message
43.77 + * @param className
43.78 + * the name of the resource class
43.79 + * @param key
43.80 + * the key for the missing resource.
43.81 + * @param cause
43.82 + * the cause (which is saved for later retrieval by the
43.83 + * {@link Throwable.getCause()} method). (A null value is
43.84 + * permitted, and indicates that the cause is nonexistent
43.85 + * or unknown.)
43.86 + */
43.87 + MissingResourceException(String message, String className, String key, Throwable cause) {
43.88 + super(message, cause);
43.89 + this.className = className;
43.90 + this.key = key;
43.91 + }
43.92 +
43.93 + /**
43.94 + * Gets parameter passed by constructor.
43.95 + *
43.96 + * @return the name of the resource class
43.97 + */
43.98 + public String getClassName() {
43.99 + return className;
43.100 + }
43.101 +
43.102 + /**
43.103 + * Gets parameter passed by constructor.
43.104 + *
43.105 + * @return the key for the missing resource
43.106 + */
43.107 + public String getKey() {
43.108 + return key;
43.109 + }
43.110 +
43.111 + //============ privates ============
43.112 +
43.113 + // serialization compatibility with JDK1.1
43.114 + private static final long serialVersionUID = -4876345176062000401L;
43.115 +
43.116 + /**
43.117 + * The class name of the resource bundle requested by the user.
43.118 + * @serial
43.119 + */
43.120 + private String className;
43.121 +
43.122 + /**
43.123 + * The name of the specific resource requested by the user.
43.124 + * @serial
43.125 + */
43.126 + private String key;
43.127 +}
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/rt/emul/compact/src/main/java/java/util/Properties.java Thu Oct 03 15:40:35 2013 +0200
44.3 @@ -0,0 +1,1114 @@
44.4 +/*
44.5 + * Copyright (c) 1995, 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.io.IOException;
44.32 +import java.io.PrintStream;
44.33 +import java.io.PrintWriter;
44.34 +import java.io.InputStream;
44.35 +import java.io.OutputStream;
44.36 +import java.io.Reader;
44.37 +import java.io.Writer;
44.38 +import java.io.OutputStreamWriter;
44.39 +import java.io.BufferedWriter;
44.40 +
44.41 +/**
44.42 + * The <code>Properties</code> class represents a persistent set of
44.43 + * properties. The <code>Properties</code> can be saved to a stream
44.44 + * or loaded from a stream. Each key and its corresponding value in
44.45 + * the property list is a string.
44.46 + * <p>
44.47 + * A property list can contain another property list as its
44.48 + * "defaults"; this second property list is searched if
44.49 + * the property key is not found in the original property list.
44.50 + * <p>
44.51 + * Because <code>Properties</code> inherits from <code>Hashtable</code>, the
44.52 + * <code>put</code> and <code>putAll</code> methods can be applied to a
44.53 + * <code>Properties</code> object. Their use is strongly discouraged as they
44.54 + * allow the caller to insert entries whose keys or values are not
44.55 + * <code>Strings</code>. The <code>setProperty</code> method should be used
44.56 + * instead. If the <code>store</code> or <code>save</code> method is called
44.57 + * on a "compromised" <code>Properties</code> object that contains a
44.58 + * non-<code>String</code> key or value, the call will fail. Similarly,
44.59 + * the call to the <code>propertyNames</code> or <code>list</code> method
44.60 + * will fail if it is called on a "compromised" <code>Properties</code>
44.61 + * object that contains a non-<code>String</code> key.
44.62 + *
44.63 + * <p>
44.64 + * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
44.65 + * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
44.66 + * methods load and store properties from and to a character based stream
44.67 + * in a simple line-oriented format specified below.
44.68 + *
44.69 + * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
44.70 + * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
44.71 + * methods work the same way as the load(Reader)/store(Writer, String) pair, except
44.72 + * the input/output stream is encoded in ISO 8859-1 character encoding.
44.73 + * Characters that cannot be directly represented in this encoding can be written using
44.74 + * Unicode escapes as defined in section 3.3 of
44.75 + * <cite>The Java™ Language Specification</cite>;
44.76 + * only a single 'u' character is allowed in an escape
44.77 + * sequence. The native2ascii tool can be used to convert property files to and
44.78 + * from other character encodings.
44.79 + *
44.80 + * <p> The {@link #loadFromXML(InputStream)} and {@link
44.81 + * #storeToXML(OutputStream, String, String)} methods load and store properties
44.82 + * in a simple XML format. By default the UTF-8 character encoding is used,
44.83 + * however a specific encoding may be specified if required. An XML properties
44.84 + * document has the following DOCTYPE declaration:
44.85 + *
44.86 + * <pre>
44.87 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
44.88 + * </pre>
44.89 + * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
44.90 + * <i>not</i> accessed when exporting or importing properties; it merely
44.91 + * serves as a string to uniquely identify the DTD, which is:
44.92 + * <pre>
44.93 + * <?xml version="1.0" encoding="UTF-8"?>
44.94 + *
44.95 + * <!-- DTD for properties -->
44.96 + *
44.97 + * <!ELEMENT properties ( comment?, entry* ) >
44.98 + *
44.99 + * <!ATTLIST properties version CDATA #FIXED "1.0">
44.100 + *
44.101 + * <!ELEMENT comment (#PCDATA) >
44.102 + *
44.103 + * <!ELEMENT entry (#PCDATA) >
44.104 + *
44.105 + * <!ATTLIST entry key CDATA #REQUIRED>
44.106 + * </pre>
44.107 + *
44.108 + * <p>This class is thread-safe: multiple threads can share a single
44.109 + * <tt>Properties</tt> object without the need for external synchronization.
44.110 + *
44.111 + * @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
44.112 + * @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
44.113 + *
44.114 + * @author Arthur van Hoff
44.115 + * @author Michael McCloskey
44.116 + * @author Xueming Shen
44.117 + * @since JDK1.0
44.118 + */
44.119 +public
44.120 +class Properties extends Hashtable<Object,Object> {
44.121 + /**
44.122 + * use serialVersionUID from JDK 1.1.X for interoperability
44.123 + */
44.124 + private static final long serialVersionUID = 4112578634029874840L;
44.125 +
44.126 + /**
44.127 + * A property list that contains default values for any keys not
44.128 + * found in this property list.
44.129 + *
44.130 + * @serial
44.131 + */
44.132 + protected Properties defaults;
44.133 +
44.134 + /**
44.135 + * Creates an empty property list with no default values.
44.136 + */
44.137 + public Properties() {
44.138 + this(null);
44.139 + }
44.140 +
44.141 + /**
44.142 + * Creates an empty property list with the specified defaults.
44.143 + *
44.144 + * @param defaults the defaults.
44.145 + */
44.146 + public Properties(Properties defaults) {
44.147 + this.defaults = defaults;
44.148 + }
44.149 +
44.150 + /**
44.151 + * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
44.152 + * parallelism with the <tt>getProperty</tt> method. Enforces use of
44.153 + * strings for property keys and values. The value returned is the
44.154 + * result of the <tt>Hashtable</tt> call to <code>put</code>.
44.155 + *
44.156 + * @param key the key to be placed into this property list.
44.157 + * @param value the value corresponding to <tt>key</tt>.
44.158 + * @return the previous value of the specified key in this property
44.159 + * list, or <code>null</code> if it did not have one.
44.160 + * @see #getProperty
44.161 + * @since 1.2
44.162 + */
44.163 + public synchronized Object setProperty(String key, String value) {
44.164 + return put(key, value);
44.165 + }
44.166 +
44.167 +
44.168 + /**
44.169 + * Reads a property list (key and element pairs) from the input
44.170 + * character stream in a simple line-oriented format.
44.171 + * <p>
44.172 + * Properties are processed in terms of lines. There are two
44.173 + * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
44.174 + * A natural line is defined as a line of
44.175 + * characters that is terminated either by a set of line terminator
44.176 + * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>)
44.177 + * or by the end of the stream. A natural line may be either a blank line,
44.178 + * a comment line, or hold all or some of a key-element pair. A logical
44.179 + * line holds all the data of a key-element pair, which may be spread
44.180 + * out across several adjacent natural lines by escaping
44.181 + * the line terminator sequence with a backslash character
44.182 + * <code>\</code>. Note that a comment line cannot be extended
44.183 + * in this manner; every natural line that is a comment must have
44.184 + * its own comment indicator, as described below. Lines are read from
44.185 + * input until the end of the stream is reached.
44.186 + *
44.187 + * <p>
44.188 + * A natural line that contains only white space characters is
44.189 + * considered blank and is ignored. A comment line has an ASCII
44.190 + * <code>'#'</code> or <code>'!'</code> as its first non-white
44.191 + * space character; comment lines are also ignored and do not
44.192 + * encode key-element information. In addition to line
44.193 + * terminators, this format considers the characters space
44.194 + * (<code>' '</code>, <code>'\u0020'</code>), tab
44.195 + * (<code>'\t'</code>, <code>'\u0009'</code>), and form feed
44.196 + * (<code>'\f'</code>, <code>'\u000C'</code>) to be white
44.197 + * space.
44.198 + *
44.199 + * <p>
44.200 + * If a logical line is spread across several natural lines, the
44.201 + * backslash escaping the line terminator sequence, the line
44.202 + * terminator sequence, and any white space at the start of the
44.203 + * following line have no affect on the key or element values.
44.204 + * The remainder of the discussion of key and element parsing
44.205 + * (when loading) will assume all the characters constituting
44.206 + * the key and element appear on a single natural line after
44.207 + * line continuation characters have been removed. Note that
44.208 + * it is <i>not</i> sufficient to only examine the character
44.209 + * preceding a line terminator sequence to decide if the line
44.210 + * terminator is escaped; there must be an odd number of
44.211 + * contiguous backslashes for the line terminator to be escaped.
44.212 + * Since the input is processed from left to right, a
44.213 + * non-zero even number of 2<i>n</i> contiguous backslashes
44.214 + * before a line terminator (or elsewhere) encodes <i>n</i>
44.215 + * backslashes after escape processing.
44.216 + *
44.217 + * <p>
44.218 + * The key contains all of the characters in the line starting
44.219 + * with the first non-white space character and up to, but not
44.220 + * including, the first unescaped <code>'='</code>,
44.221 + * <code>':'</code>, or white space character other than a line
44.222 + * terminator. All of these key termination characters may be
44.223 + * included in the key by escaping them with a preceding backslash
44.224 + * character; for example,<p>
44.225 + *
44.226 + * <code>\:\=</code><p>
44.227 + *
44.228 + * would be the two-character key <code>":="</code>. Line
44.229 + * terminator characters can be included using <code>\r</code> and
44.230 + * <code>\n</code> escape sequences. Any white space after the
44.231 + * key is skipped; if the first non-white space character after
44.232 + * the key is <code>'='</code> or <code>':'</code>, then it is
44.233 + * ignored and any white space characters after it are also
44.234 + * skipped. All remaining characters on the line become part of
44.235 + * the associated element string; if there are no remaining
44.236 + * characters, the element is the empty string
44.237 + * <code>""</code>. Once the raw character sequences
44.238 + * constituting the key and element are identified, escape
44.239 + * processing is performed as described above.
44.240 + *
44.241 + * <p>
44.242 + * As an example, each of the following three lines specifies the key
44.243 + * <code>"Truth"</code> and the associated element value
44.244 + * <code>"Beauty"</code>:
44.245 + * <p>
44.246 + * <pre>
44.247 + * Truth = Beauty
44.248 + * Truth:Beauty
44.249 + * Truth :Beauty
44.250 + * </pre>
44.251 + * As another example, the following three lines specify a single
44.252 + * property:
44.253 + * <p>
44.254 + * <pre>
44.255 + * fruits apple, banana, pear, \
44.256 + * cantaloupe, watermelon, \
44.257 + * kiwi, mango
44.258 + * </pre>
44.259 + * The key is <code>"fruits"</code> and the associated element is:
44.260 + * <p>
44.261 + * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
44.262 + * Note that a space appears before each <code>\</code> so that a space
44.263 + * will appear after each comma in the final result; the <code>\</code>,
44.264 + * line terminator, and leading white space on the continuation line are
44.265 + * merely discarded and are <i>not</i> replaced by one or more other
44.266 + * characters.
44.267 + * <p>
44.268 + * As a third example, the line:
44.269 + * <p>
44.270 + * <pre>cheeses
44.271 + * </pre>
44.272 + * specifies that the key is <code>"cheeses"</code> and the associated
44.273 + * element is the empty string <code>""</code>.<p>
44.274 + * <p>
44.275 + *
44.276 + * <a name="unicodeescapes"></a>
44.277 + * Characters in keys and elements can be represented in escape
44.278 + * sequences similar to those used for character and string literals
44.279 + * (see sections 3.3 and 3.10.6 of
44.280 + * <cite>The Java™ Language Specification</cite>).
44.281 + *
44.282 + * The differences from the character escape sequences and Unicode
44.283 + * escapes used for characters and strings are:
44.284 + *
44.285 + * <ul>
44.286 + * <li> Octal escapes are not recognized.
44.287 + *
44.288 + * <li> The character sequence <code>\b</code> does <i>not</i>
44.289 + * represent a backspace character.
44.290 + *
44.291 + * <li> The method does not treat a backslash character,
44.292 + * <code>\</code>, before a non-valid escape character as an
44.293 + * error; the backslash is silently dropped. For example, in a
44.294 + * Java string the sequence <code>"\z"</code> would cause a
44.295 + * compile time error. In contrast, this method silently drops
44.296 + * the backslash. Therefore, this method treats the two character
44.297 + * sequence <code>"\b"</code> as equivalent to the single
44.298 + * character <code>'b'</code>.
44.299 + *
44.300 + * <li> Escapes are not necessary for single and double quotes;
44.301 + * however, by the rule above, single and double quote characters
44.302 + * preceded by a backslash still yield single and double quote
44.303 + * characters, respectively.
44.304 + *
44.305 + * <li> Only a single 'u' character is allowed in a Uniocde escape
44.306 + * sequence.
44.307 + *
44.308 + * </ul>
44.309 + * <p>
44.310 + * The specified stream remains open after this method returns.
44.311 + *
44.312 + * @param reader the input character stream.
44.313 + * @throws IOException if an error occurred when reading from the
44.314 + * input stream.
44.315 + * @throws IllegalArgumentException if a malformed Unicode escape
44.316 + * appears in the input.
44.317 + * @since 1.6
44.318 + */
44.319 + public synchronized void load(Reader reader) throws IOException {
44.320 + load0(new LineReader(reader));
44.321 + }
44.322 +
44.323 + /**
44.324 + * Reads a property list (key and element pairs) from the input
44.325 + * byte stream. The input stream is in a simple line-oriented
44.326 + * format as specified in
44.327 + * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
44.328 + * the ISO 8859-1 character encoding; that is each byte is one Latin1
44.329 + * character. Characters not in Latin1, and certain special characters,
44.330 + * are represented in keys and elements using Unicode escapes as defined in
44.331 + * section 3.3 of
44.332 + * <cite>The Java™ Language Specification</cite>.
44.333 + * <p>
44.334 + * The specified stream remains open after this method returns.
44.335 + *
44.336 + * @param inStream the input stream.
44.337 + * @exception IOException if an error occurred when reading from the
44.338 + * input stream.
44.339 + * @throws IllegalArgumentException if the input stream contains a
44.340 + * malformed Unicode escape sequence.
44.341 + * @since 1.2
44.342 + */
44.343 + public synchronized void load(InputStream inStream) throws IOException {
44.344 + load0(new LineReader(inStream));
44.345 + }
44.346 +
44.347 + private void load0 (LineReader lr) throws IOException {
44.348 + char[] convtBuf = new char[1024];
44.349 + int limit;
44.350 + int keyLen;
44.351 + int valueStart;
44.352 + char c;
44.353 + boolean hasSep;
44.354 + boolean precedingBackslash;
44.355 +
44.356 + while ((limit = lr.readLine()) >= 0) {
44.357 + c = 0;
44.358 + keyLen = 0;
44.359 + valueStart = limit;
44.360 + hasSep = false;
44.361 +
44.362 + //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
44.363 + precedingBackslash = false;
44.364 + while (keyLen < limit) {
44.365 + c = lr.lineBuf[keyLen];
44.366 + //need check if escaped.
44.367 + if ((c == '=' || c == ':') && !precedingBackslash) {
44.368 + valueStart = keyLen + 1;
44.369 + hasSep = true;
44.370 + break;
44.371 + } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
44.372 + valueStart = keyLen + 1;
44.373 + break;
44.374 + }
44.375 + if (c == '\\') {
44.376 + precedingBackslash = !precedingBackslash;
44.377 + } else {
44.378 + precedingBackslash = false;
44.379 + }
44.380 + keyLen++;
44.381 + }
44.382 + while (valueStart < limit) {
44.383 + c = lr.lineBuf[valueStart];
44.384 + if (c != ' ' && c != '\t' && c != '\f') {
44.385 + if (!hasSep && (c == '=' || c == ':')) {
44.386 + hasSep = true;
44.387 + } else {
44.388 + break;
44.389 + }
44.390 + }
44.391 + valueStart++;
44.392 + }
44.393 + String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
44.394 + String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
44.395 + put(key, value);
44.396 + }
44.397 + }
44.398 +
44.399 + /* Read in a "logical line" from an InputStream/Reader, skip all comment
44.400 + * and blank lines and filter out those leading whitespace characters
44.401 + * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
44.402 + * Method returns the char length of the "logical line" and stores
44.403 + * the line in "lineBuf".
44.404 + */
44.405 + class LineReader {
44.406 + public LineReader(InputStream inStream) {
44.407 + this.inStream = inStream;
44.408 + inByteBuf = new byte[8192];
44.409 + }
44.410 +
44.411 + public LineReader(Reader reader) {
44.412 + this.reader = reader;
44.413 + inCharBuf = new char[8192];
44.414 + }
44.415 +
44.416 + byte[] inByteBuf;
44.417 + char[] inCharBuf;
44.418 + char[] lineBuf = new char[1024];
44.419 + int inLimit = 0;
44.420 + int inOff = 0;
44.421 + InputStream inStream;
44.422 + Reader reader;
44.423 +
44.424 + int readLine() throws IOException {
44.425 + int len = 0;
44.426 + char c = 0;
44.427 +
44.428 + boolean skipWhiteSpace = true;
44.429 + boolean isCommentLine = false;
44.430 + boolean isNewLine = true;
44.431 + boolean appendedLineBegin = false;
44.432 + boolean precedingBackslash = false;
44.433 + boolean skipLF = false;
44.434 +
44.435 + while (true) {
44.436 + if (inOff >= inLimit) {
44.437 + inLimit = (inStream==null)?reader.read(inCharBuf)
44.438 + :inStream.read(inByteBuf);
44.439 + inOff = 0;
44.440 + if (inLimit <= 0) {
44.441 + if (len == 0 || isCommentLine) {
44.442 + return -1;
44.443 + }
44.444 + return len;
44.445 + }
44.446 + }
44.447 + if (inStream != null) {
44.448 + //The line below is equivalent to calling a
44.449 + //ISO8859-1 decoder.
44.450 + c = (char) (0xff & inByteBuf[inOff++]);
44.451 + } else {
44.452 + c = inCharBuf[inOff++];
44.453 + }
44.454 + if (skipLF) {
44.455 + skipLF = false;
44.456 + if (c == '\n') {
44.457 + continue;
44.458 + }
44.459 + }
44.460 + if (skipWhiteSpace) {
44.461 + if (c == ' ' || c == '\t' || c == '\f') {
44.462 + continue;
44.463 + }
44.464 + if (!appendedLineBegin && (c == '\r' || c == '\n')) {
44.465 + continue;
44.466 + }
44.467 + skipWhiteSpace = false;
44.468 + appendedLineBegin = false;
44.469 + }
44.470 + if (isNewLine) {
44.471 + isNewLine = false;
44.472 + if (c == '#' || c == '!') {
44.473 + isCommentLine = true;
44.474 + continue;
44.475 + }
44.476 + }
44.477 +
44.478 + if (c != '\n' && c != '\r') {
44.479 + lineBuf[len++] = c;
44.480 + if (len == lineBuf.length) {
44.481 + int newLength = lineBuf.length * 2;
44.482 + if (newLength < 0) {
44.483 + newLength = Integer.MAX_VALUE;
44.484 + }
44.485 + char[] buf = new char[newLength];
44.486 + System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
44.487 + lineBuf = buf;
44.488 + }
44.489 + //flip the preceding backslash flag
44.490 + if (c == '\\') {
44.491 + precedingBackslash = !precedingBackslash;
44.492 + } else {
44.493 + precedingBackslash = false;
44.494 + }
44.495 + }
44.496 + else {
44.497 + // reached EOL
44.498 + if (isCommentLine || len == 0) {
44.499 + isCommentLine = false;
44.500 + isNewLine = true;
44.501 + skipWhiteSpace = true;
44.502 + len = 0;
44.503 + continue;
44.504 + }
44.505 + if (inOff >= inLimit) {
44.506 + inLimit = (inStream==null)
44.507 + ?reader.read(inCharBuf)
44.508 + :inStream.read(inByteBuf);
44.509 + inOff = 0;
44.510 + if (inLimit <= 0) {
44.511 + return len;
44.512 + }
44.513 + }
44.514 + if (precedingBackslash) {
44.515 + len -= 1;
44.516 + //skip the leading whitespace characters in following line
44.517 + skipWhiteSpace = true;
44.518 + appendedLineBegin = true;
44.519 + precedingBackslash = false;
44.520 + if (c == '\r') {
44.521 + skipLF = true;
44.522 + }
44.523 + } else {
44.524 + return len;
44.525 + }
44.526 + }
44.527 + }
44.528 + }
44.529 + }
44.530 +
44.531 + /*
44.532 + * Converts encoded \uxxxx to unicode chars
44.533 + * and changes special saved chars to their original forms
44.534 + */
44.535 + private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
44.536 + if (convtBuf.length < len) {
44.537 + int newLen = len * 2;
44.538 + if (newLen < 0) {
44.539 + newLen = Integer.MAX_VALUE;
44.540 + }
44.541 + convtBuf = new char[newLen];
44.542 + }
44.543 + char aChar;
44.544 + char[] out = convtBuf;
44.545 + int outLen = 0;
44.546 + int end = off + len;
44.547 +
44.548 + while (off < end) {
44.549 + aChar = in[off++];
44.550 + if (aChar == '\\') {
44.551 + aChar = in[off++];
44.552 + if(aChar == 'u') {
44.553 + // Read the xxxx
44.554 + int value=0;
44.555 + for (int i=0; i<4; i++) {
44.556 + aChar = in[off++];
44.557 + switch (aChar) {
44.558 + case '0': case '1': case '2': case '3': case '4':
44.559 + case '5': case '6': case '7': case '8': case '9':
44.560 + value = (value << 4) + aChar - '0';
44.561 + break;
44.562 + case 'a': case 'b': case 'c':
44.563 + case 'd': case 'e': case 'f':
44.564 + value = (value << 4) + 10 + aChar - 'a';
44.565 + break;
44.566 + case 'A': case 'B': case 'C':
44.567 + case 'D': case 'E': case 'F':
44.568 + value = (value << 4) + 10 + aChar - 'A';
44.569 + break;
44.570 + default:
44.571 + throw new IllegalArgumentException(
44.572 + "Malformed \\uxxxx encoding.");
44.573 + }
44.574 + }
44.575 + out[outLen++] = (char)value;
44.576 + } else {
44.577 + if (aChar == 't') aChar = '\t';
44.578 + else if (aChar == 'r') aChar = '\r';
44.579 + else if (aChar == 'n') aChar = '\n';
44.580 + else if (aChar == 'f') aChar = '\f';
44.581 + out[outLen++] = aChar;
44.582 + }
44.583 + } else {
44.584 + out[outLen++] = aChar;
44.585 + }
44.586 + }
44.587 + return new String (out, 0, outLen);
44.588 + }
44.589 +
44.590 + /*
44.591 + * Converts unicodes to encoded \uxxxx and escapes
44.592 + * special characters with a preceding slash
44.593 + */
44.594 + private String saveConvert(String theString,
44.595 + boolean escapeSpace,
44.596 + boolean escapeUnicode) {
44.597 + int len = theString.length();
44.598 + int bufLen = len * 2;
44.599 + if (bufLen < 0) {
44.600 + bufLen = Integer.MAX_VALUE;
44.601 + }
44.602 + StringBuffer outBuffer = new StringBuffer(bufLen);
44.603 +
44.604 + for(int x=0; x<len; x++) {
44.605 + char aChar = theString.charAt(x);
44.606 + // Handle common case first, selecting largest block that
44.607 + // avoids the specials below
44.608 + if ((aChar > 61) && (aChar < 127)) {
44.609 + if (aChar == '\\') {
44.610 + outBuffer.append('\\'); outBuffer.append('\\');
44.611 + continue;
44.612 + }
44.613 + outBuffer.append(aChar);
44.614 + continue;
44.615 + }
44.616 + switch(aChar) {
44.617 + case ' ':
44.618 + if (x == 0 || escapeSpace)
44.619 + outBuffer.append('\\');
44.620 + outBuffer.append(' ');
44.621 + break;
44.622 + case '\t':outBuffer.append('\\'); outBuffer.append('t');
44.623 + break;
44.624 + case '\n':outBuffer.append('\\'); outBuffer.append('n');
44.625 + break;
44.626 + case '\r':outBuffer.append('\\'); outBuffer.append('r');
44.627 + break;
44.628 + case '\f':outBuffer.append('\\'); outBuffer.append('f');
44.629 + break;
44.630 + case '=': // Fall through
44.631 + case ':': // Fall through
44.632 + case '#': // Fall through
44.633 + case '!':
44.634 + outBuffer.append('\\'); outBuffer.append(aChar);
44.635 + break;
44.636 + default:
44.637 + if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
44.638 + outBuffer.append('\\');
44.639 + outBuffer.append('u');
44.640 + outBuffer.append(toHex((aChar >> 12) & 0xF));
44.641 + outBuffer.append(toHex((aChar >> 8) & 0xF));
44.642 + outBuffer.append(toHex((aChar >> 4) & 0xF));
44.643 + outBuffer.append(toHex( aChar & 0xF));
44.644 + } else {
44.645 + outBuffer.append(aChar);
44.646 + }
44.647 + }
44.648 + }
44.649 + return outBuffer.toString();
44.650 + }
44.651 +
44.652 + private static void writeComments(BufferedWriter bw, String comments)
44.653 + throws IOException {
44.654 + bw.write("#");
44.655 + int len = comments.length();
44.656 + int current = 0;
44.657 + int last = 0;
44.658 + char[] uu = new char[6];
44.659 + uu[0] = '\\';
44.660 + uu[1] = 'u';
44.661 + while (current < len) {
44.662 + char c = comments.charAt(current);
44.663 + if (c > '\u00ff' || c == '\n' || c == '\r') {
44.664 + if (last != current)
44.665 + bw.write(comments.substring(last, current));
44.666 + if (c > '\u00ff') {
44.667 + uu[2] = toHex((c >> 12) & 0xf);
44.668 + uu[3] = toHex((c >> 8) & 0xf);
44.669 + uu[4] = toHex((c >> 4) & 0xf);
44.670 + uu[5] = toHex( c & 0xf);
44.671 + bw.write(new String(uu));
44.672 + } else {
44.673 + bw.newLine();
44.674 + if (c == '\r' &&
44.675 + current != len - 1 &&
44.676 + comments.charAt(current + 1) == '\n') {
44.677 + current++;
44.678 + }
44.679 + if (current == len - 1 ||
44.680 + (comments.charAt(current + 1) != '#' &&
44.681 + comments.charAt(current + 1) != '!'))
44.682 + bw.write("#");
44.683 + }
44.684 + last = current + 1;
44.685 + }
44.686 + current++;
44.687 + }
44.688 + if (last != current)
44.689 + bw.write(comments.substring(last, current));
44.690 + bw.newLine();
44.691 + }
44.692 +
44.693 + /**
44.694 + * Calls the <code>store(OutputStream out, String comments)</code> method
44.695 + * and suppresses IOExceptions that were thrown.
44.696 + *
44.697 + * @deprecated This method does not throw an IOException if an I/O error
44.698 + * occurs while saving the property list. The preferred way to save a
44.699 + * properties list is via the <code>store(OutputStream out,
44.700 + * String comments)</code> method or the
44.701 + * <code>storeToXML(OutputStream os, String comment)</code> method.
44.702 + *
44.703 + * @param out an output stream.
44.704 + * @param comments a description of the property list.
44.705 + * @exception ClassCastException if this <code>Properties</code> object
44.706 + * contains any keys or values that are not
44.707 + * <code>Strings</code>.
44.708 + */
44.709 + @Deprecated
44.710 + public void save(OutputStream out, String comments) {
44.711 + try {
44.712 + store(out, comments);
44.713 + } catch (IOException e) {
44.714 + }
44.715 + }
44.716 +
44.717 + /**
44.718 + * Writes this property list (key and element pairs) in this
44.719 + * <code>Properties</code> table to the output character stream in a
44.720 + * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
44.721 + * method.
44.722 + * <p>
44.723 + * Properties from the defaults table of this <code>Properties</code>
44.724 + * table (if any) are <i>not</i> written out by this method.
44.725 + * <p>
44.726 + * If the comments argument is not null, then an ASCII <code>#</code>
44.727 + * character, the comments string, and a line separator are first written
44.728 + * to the output stream. Thus, the <code>comments</code> can serve as an
44.729 + * identifying comment. Any one of a line feed ('\n'), a carriage
44.730 + * return ('\r'), or a carriage return followed immediately by a line feed
44.731 + * in comments is replaced by a line separator generated by the <code>Writer</code>
44.732 + * and if the next character in comments is not character <code>#</code> or
44.733 + * character <code>!</code> then an ASCII <code>#</code> is written out
44.734 + * after that line separator.
44.735 + * <p>
44.736 + * Next, a comment line is always written, consisting of an ASCII
44.737 + * <code>#</code> character, the current date and time (as if produced
44.738 + * by the <code>toString</code> method of <code>Date</code> for the
44.739 + * current time), and a line separator as generated by the <code>Writer</code>.
44.740 + * <p>
44.741 + * Then every entry in this <code>Properties</code> table is
44.742 + * written out, one per line. For each entry the key string is
44.743 + * written, then an ASCII <code>=</code>, then the associated
44.744 + * element string. For the key, all space characters are
44.745 + * written with a preceding <code>\</code> character. For the
44.746 + * element, leading space characters, but not embedded or trailing
44.747 + * space characters, are written with a preceding <code>\</code>
44.748 + * character. The key and element characters <code>#</code>,
44.749 + * <code>!</code>, <code>=</code>, and <code>:</code> are written
44.750 + * with a preceding backslash to ensure that they are properly loaded.
44.751 + * <p>
44.752 + * After the entries have been written, the output stream is flushed.
44.753 + * The output stream remains open after this method returns.
44.754 + * <p>
44.755 + *
44.756 + * @param writer an output character stream writer.
44.757 + * @param comments a description of the property list.
44.758 + * @exception IOException if writing this property list to the specified
44.759 + * output stream throws an <tt>IOException</tt>.
44.760 + * @exception ClassCastException if this <code>Properties</code> object
44.761 + * contains any keys or values that are not <code>Strings</code>.
44.762 + * @exception NullPointerException if <code>writer</code> is null.
44.763 + * @since 1.6
44.764 + */
44.765 + public void store(Writer writer, String comments)
44.766 + throws IOException
44.767 + {
44.768 + store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
44.769 + : new BufferedWriter(writer),
44.770 + comments,
44.771 + false);
44.772 + }
44.773 +
44.774 + /**
44.775 + * Writes this property list (key and element pairs) in this
44.776 + * <code>Properties</code> table to the output stream in a format suitable
44.777 + * for loading into a <code>Properties</code> table using the
44.778 + * {@link #load(InputStream) load(InputStream)} method.
44.779 + * <p>
44.780 + * Properties from the defaults table of this <code>Properties</code>
44.781 + * table (if any) are <i>not</i> written out by this method.
44.782 + * <p>
44.783 + * This method outputs the comments, properties keys and values in
44.784 + * the same format as specified in
44.785 + * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
44.786 + * with the following differences:
44.787 + * <ul>
44.788 + * <li>The stream is written using the ISO 8859-1 character encoding.
44.789 + *
44.790 + * <li>Characters not in Latin-1 in the comments are written as
44.791 + * <code>\u</code><i>xxxx</i> for their appropriate unicode
44.792 + * hexadecimal value <i>xxxx</i>.
44.793 + *
44.794 + * <li>Characters less than <code>\u0020</code> and characters greater
44.795 + * than <code>\u007E</code> in property keys or values are written
44.796 + * as <code>\u</code><i>xxxx</i> for the appropriate hexadecimal
44.797 + * value <i>xxxx</i>.
44.798 + * </ul>
44.799 + * <p>
44.800 + * After the entries have been written, the output stream is flushed.
44.801 + * The output stream remains open after this method returns.
44.802 + * <p>
44.803 + * @param out an output stream.
44.804 + * @param comments a description of the property list.
44.805 + * @exception IOException if writing this property list to the specified
44.806 + * output stream throws an <tt>IOException</tt>.
44.807 + * @exception ClassCastException if this <code>Properties</code> object
44.808 + * contains any keys or values that are not <code>Strings</code>.
44.809 + * @exception NullPointerException if <code>out</code> is null.
44.810 + * @since 1.2
44.811 + */
44.812 + public void store(OutputStream out, String comments)
44.813 + throws IOException
44.814 + {
44.815 + store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
44.816 + comments,
44.817 + true);
44.818 + }
44.819 +
44.820 + private void store0(BufferedWriter bw, String comments, boolean escUnicode)
44.821 + throws IOException
44.822 + {
44.823 + if (comments != null) {
44.824 + writeComments(bw, comments);
44.825 + }
44.826 + bw.write("#" + new Date().toString());
44.827 + bw.newLine();
44.828 + synchronized (this) {
44.829 + for (Enumeration e = keys(); e.hasMoreElements();) {
44.830 + String key = (String)e.nextElement();
44.831 + String val = (String)get(key);
44.832 + key = saveConvert(key, true, escUnicode);
44.833 + /* No need to escape embedded and trailing spaces for value, hence
44.834 + * pass false to flag.
44.835 + */
44.836 + val = saveConvert(val, false, escUnicode);
44.837 + bw.write(key + "=" + val);
44.838 + bw.newLine();
44.839 + }
44.840 + }
44.841 + bw.flush();
44.842 + }
44.843 +
44.844 + /**
44.845 + * Loads all of the properties represented by the XML document on the
44.846 + * specified input stream into this properties table.
44.847 + *
44.848 + * <p>The XML document must have the following DOCTYPE declaration:
44.849 + * <pre>
44.850 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
44.851 + * </pre>
44.852 + * Furthermore, the document must satisfy the properties DTD described
44.853 + * above.
44.854 + *
44.855 + * <p>The specified stream is closed after this method returns.
44.856 + *
44.857 + * @param in the input stream from which to read the XML document.
44.858 + * @throws IOException if reading from the specified input stream
44.859 + * results in an <tt>IOException</tt>.
44.860 + * @throws InvalidPropertiesFormatException Data on input stream does not
44.861 + * constitute a valid XML document with the mandated document type.
44.862 + * @throws NullPointerException if <code>in</code> is null.
44.863 + * @see #storeToXML(OutputStream, String, String)
44.864 + * @since 1.5
44.865 + */
44.866 + public synchronized void loadFromXML(InputStream in)
44.867 + throws IOException, InvalidPropertiesFormatException
44.868 + {
44.869 + if (in == null)
44.870 + throw new NullPointerException();
44.871 + XMLUtils.load(this, in);
44.872 + in.close();
44.873 + }
44.874 +
44.875 + /**
44.876 + * Emits an XML document representing all of the properties contained
44.877 + * in this table.
44.878 + *
44.879 + * <p> An invocation of this method of the form <tt>props.storeToXML(os,
44.880 + * comment)</tt> behaves in exactly the same way as the invocation
44.881 + * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
44.882 + *
44.883 + * @param os the output stream on which to emit the XML document.
44.884 + * @param comment a description of the property list, or <code>null</code>
44.885 + * if no comment is desired.
44.886 + * @throws IOException if writing to the specified output stream
44.887 + * results in an <tt>IOException</tt>.
44.888 + * @throws NullPointerException if <code>os</code> is null.
44.889 + * @throws ClassCastException if this <code>Properties</code> object
44.890 + * contains any keys or values that are not
44.891 + * <code>Strings</code>.
44.892 + * @see #loadFromXML(InputStream)
44.893 + * @since 1.5
44.894 + */
44.895 + public void storeToXML(OutputStream os, String comment)
44.896 + throws IOException
44.897 + {
44.898 + if (os == null)
44.899 + throw new NullPointerException();
44.900 + storeToXML(os, comment, "UTF-8");
44.901 + }
44.902 +
44.903 + /**
44.904 + * Emits an XML document representing all of the properties contained
44.905 + * in this table, using the specified encoding.
44.906 + *
44.907 + * <p>The XML document will have the following DOCTYPE declaration:
44.908 + * <pre>
44.909 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
44.910 + * </pre>
44.911 + *
44.912 + *<p>If the specified comment is <code>null</code> then no comment
44.913 + * will be stored in the document.
44.914 + *
44.915 + * <p>The specified stream remains open after this method returns.
44.916 + *
44.917 + * @param os the output stream on which to emit the XML document.
44.918 + * @param comment a description of the property list, or <code>null</code>
44.919 + * if no comment is desired.
44.920 + * @param encoding the name of a supported
44.921 + * <a href="../lang/package-summary.html#charenc">
44.922 + * character encoding</a>
44.923 + *
44.924 + * @throws IOException if writing to the specified output stream
44.925 + * results in an <tt>IOException</tt>.
44.926 + * @throws NullPointerException if <code>os</code> is <code>null</code>,
44.927 + * or if <code>encoding</code> is <code>null</code>.
44.928 + * @throws ClassCastException if this <code>Properties</code> object
44.929 + * contains any keys or values that are not
44.930 + * <code>Strings</code>.
44.931 + * @see #loadFromXML(InputStream)
44.932 + * @since 1.5
44.933 + */
44.934 + public void storeToXML(OutputStream os, String comment, String encoding)
44.935 + throws IOException
44.936 + {
44.937 + if (os == null)
44.938 + throw new NullPointerException();
44.939 + XMLUtils.save(this, os, comment, encoding);
44.940 + }
44.941 +
44.942 + /**
44.943 + * Searches for the property with the specified key in this property list.
44.944 + * If the key is not found in this property list, the default property list,
44.945 + * and its defaults, recursively, are then checked. The method returns
44.946 + * <code>null</code> if the property is not found.
44.947 + *
44.948 + * @param key the property key.
44.949 + * @return the value in this property list with the specified key value.
44.950 + * @see #setProperty
44.951 + * @see #defaults
44.952 + */
44.953 + public String getProperty(String key) {
44.954 + Object oval = super.get(key);
44.955 + String sval = (oval instanceof String) ? (String)oval : null;
44.956 + return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
44.957 + }
44.958 +
44.959 + /**
44.960 + * Searches for the property with the specified key in this property list.
44.961 + * If the key is not found in this property list, the default property list,
44.962 + * and its defaults, recursively, are then checked. The method returns the
44.963 + * default value argument if the property is not found.
44.964 + *
44.965 + * @param key the hashtable key.
44.966 + * @param defaultValue a default value.
44.967 + *
44.968 + * @return the value in this property list with the specified key value.
44.969 + * @see #setProperty
44.970 + * @see #defaults
44.971 + */
44.972 + public String getProperty(String key, String defaultValue) {
44.973 + String val = getProperty(key);
44.974 + return (val == null) ? defaultValue : val;
44.975 + }
44.976 +
44.977 + /**
44.978 + * Returns an enumeration of all the keys in this property list,
44.979 + * including distinct keys in the default property list if a key
44.980 + * of the same name has not already been found from the main
44.981 + * properties list.
44.982 + *
44.983 + * @return an enumeration of all the keys in this property list, including
44.984 + * the keys in the default property list.
44.985 + * @throws ClassCastException if any key in this property list
44.986 + * is not a string.
44.987 + * @see java.util.Enumeration
44.988 + * @see java.util.Properties#defaults
44.989 + * @see #stringPropertyNames
44.990 + */
44.991 + public Enumeration<?> propertyNames() {
44.992 + Hashtable h = new Hashtable();
44.993 + enumerate(h);
44.994 + return h.keys();
44.995 + }
44.996 +
44.997 + /**
44.998 + * Returns a set of keys in this property list where
44.999 + * the key and its corresponding value are strings,
44.1000 + * including distinct keys in the default property list if a key
44.1001 + * of the same name has not already been found from the main
44.1002 + * properties list. Properties whose key or value is not
44.1003 + * of type <tt>String</tt> are omitted.
44.1004 + * <p>
44.1005 + * The returned set is not backed by the <tt>Properties</tt> object.
44.1006 + * Changes to this <tt>Properties</tt> are not reflected in the set,
44.1007 + * or vice versa.
44.1008 + *
44.1009 + * @return a set of keys in this property list where
44.1010 + * the key and its corresponding value are strings,
44.1011 + * including the keys in the default property list.
44.1012 + * @see java.util.Properties#defaults
44.1013 + * @since 1.6
44.1014 + */
44.1015 + public Set<String> stringPropertyNames() {
44.1016 + Hashtable<String, String> h = new Hashtable<>();
44.1017 + enumerateStringProperties(h);
44.1018 + return h.keySet();
44.1019 + }
44.1020 +
44.1021 + /**
44.1022 + * Prints this property list out to the specified output stream.
44.1023 + * This method is useful for debugging.
44.1024 + *
44.1025 + * @param out an output stream.
44.1026 + * @throws ClassCastException if any key in this property list
44.1027 + * is not a string.
44.1028 + */
44.1029 + public void list(PrintStream out) {
44.1030 + out.println("-- listing properties --");
44.1031 + Hashtable h = new Hashtable();
44.1032 + enumerate(h);
44.1033 + for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
44.1034 + String key = (String)e.nextElement();
44.1035 + String val = (String)h.get(key);
44.1036 + if (val.length() > 40) {
44.1037 + val = val.substring(0, 37) + "...";
44.1038 + }
44.1039 + out.println(key + "=" + val);
44.1040 + }
44.1041 + }
44.1042 +
44.1043 + /**
44.1044 + * Prints this property list out to the specified output stream.
44.1045 + * This method is useful for debugging.
44.1046 + *
44.1047 + * @param out an output stream.
44.1048 + * @throws ClassCastException if any key in this property list
44.1049 + * is not a string.
44.1050 + * @since JDK1.1
44.1051 + */
44.1052 + /*
44.1053 + * Rather than use an anonymous inner class to share common code, this
44.1054 + * method is duplicated in order to ensure that a non-1.1 compiler can
44.1055 + * compile this file.
44.1056 + */
44.1057 + public void list(PrintWriter out) {
44.1058 + out.println("-- listing properties --");
44.1059 + Hashtable h = new Hashtable();
44.1060 + enumerate(h);
44.1061 + for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
44.1062 + String key = (String)e.nextElement();
44.1063 + String val = (String)h.get(key);
44.1064 + if (val.length() > 40) {
44.1065 + val = val.substring(0, 37) + "...";
44.1066 + }
44.1067 + out.println(key + "=" + val);
44.1068 + }
44.1069 + }
44.1070 +
44.1071 + /**
44.1072 + * Enumerates all key/value pairs in the specified hashtable.
44.1073 + * @param h the hashtable
44.1074 + * @throws ClassCastException if any of the property keys
44.1075 + * is not of String type.
44.1076 + */
44.1077 + private synchronized void enumerate(Hashtable h) {
44.1078 + if (defaults != null) {
44.1079 + defaults.enumerate(h);
44.1080 + }
44.1081 + for (Enumeration e = keys() ; e.hasMoreElements() ;) {
44.1082 + String key = (String)e.nextElement();
44.1083 + h.put(key, get(key));
44.1084 + }
44.1085 + }
44.1086 +
44.1087 + /**
44.1088 + * Enumerates all key/value pairs in the specified hashtable
44.1089 + * and omits the property if the key or value is not a string.
44.1090 + * @param h the hashtable
44.1091 + */
44.1092 + private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
44.1093 + if (defaults != null) {
44.1094 + defaults.enumerateStringProperties(h);
44.1095 + }
44.1096 + for (Enumeration e = keys() ; e.hasMoreElements() ;) {
44.1097 + Object k = e.nextElement();
44.1098 + Object v = get(k);
44.1099 + if (k instanceof String && v instanceof String) {
44.1100 + h.put((String) k, (String) v);
44.1101 + }
44.1102 + }
44.1103 + }
44.1104 +
44.1105 + /**
44.1106 + * Convert a nibble to a hex character
44.1107 + * @param nibble the nibble to convert.
44.1108 + */
44.1109 + private static char toHex(int nibble) {
44.1110 + return hexDigit[(nibble & 0xF)];
44.1111 + }
44.1112 +
44.1113 + /** A table of hex digits */
44.1114 + private static final char[] hexDigit = {
44.1115 + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
44.1116 + };
44.1117 +}
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/rt/emul/compact/src/main/java/java/util/PropertyResourceBundle.java Thu Oct 03 15:40:35 2013 +0200
45.3 @@ -0,0 +1,190 @@
45.4 +/*
45.5 + * Copyright (c) 1996, 2006, 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 +package java.util;
45.44 +
45.45 +import java.io.InputStream;
45.46 +import java.io.Reader;
45.47 +import java.io.IOException;
45.48 +import sun.util.ResourceBundleEnumeration;
45.49 +
45.50 +/**
45.51 + * <code>PropertyResourceBundle</code> is a concrete subclass of
45.52 + * <code>ResourceBundle</code> that manages resources for a locale
45.53 + * using a set of static strings from a property file. See
45.54 + * {@link ResourceBundle ResourceBundle} for more information about resource
45.55 + * bundles.
45.56 + *
45.57 + * <p>
45.58 + * Unlike other types of resource bundle, you don't subclass
45.59 + * <code>PropertyResourceBundle</code>. Instead, you supply properties
45.60 + * files containing the resource data. <code>ResourceBundle.getBundle</code>
45.61 + * will automatically look for the appropriate properties file and create a
45.62 + * <code>PropertyResourceBundle</code> that refers to it. See
45.63 + * {@link ResourceBundle#getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) ResourceBundle.getBundle}
45.64 + * for a complete description of the search and instantiation strategy.
45.65 + *
45.66 + * <p>
45.67 + * The following <a name="sample">example</a> shows a member of a resource
45.68 + * bundle family with the base name "MyResources".
45.69 + * The text defines the bundle "MyResources_de",
45.70 + * the German member of the bundle family.
45.71 + * This member is based on <code>PropertyResourceBundle</code>, and the text
45.72 + * therefore is the content of the file "MyResources_de.properties"
45.73 + * (a related <a href="ListResourceBundle.html#sample">example</a> shows
45.74 + * how you can add bundles to this family that are implemented as subclasses
45.75 + * of <code>ListResourceBundle</code>).
45.76 + * The keys in this example are of the form "s1" etc. The actual
45.77 + * keys are entirely up to your choice, so long as they are the same as
45.78 + * the keys you use in your program to retrieve the objects from the bundle.
45.79 + * Keys are case-sensitive.
45.80 + * <blockquote>
45.81 + * <pre>
45.82 + * # MessageFormat pattern
45.83 + * s1=Die Platte \"{1}\" enthält {0}.
45.84 + *
45.85 + * # location of {0} in pattern
45.86 + * s2=1
45.87 + *
45.88 + * # sample disk name
45.89 + * s3=Meine Platte
45.90 + *
45.91 + * # first ChoiceFormat choice
45.92 + * s4=keine Dateien
45.93 + *
45.94 + * # second ChoiceFormat choice
45.95 + * s5=eine Datei
45.96 + *
45.97 + * # third ChoiceFormat choice
45.98 + * s6={0,number} Dateien
45.99 + *
45.100 + * # sample date
45.101 + * s7=3. März 1996
45.102 + * </pre>
45.103 + * </blockquote>
45.104 + *
45.105 + * <p>
45.106 + * <strong>Note:</strong> PropertyResourceBundle can be constructed either
45.107 + * from an InputStream or a Reader, which represents a property file.
45.108 + * Constructing a PropertyResourceBundle instance from an InputStream requires
45.109 + * that the input stream be encoded in ISO-8859-1. In that case, characters
45.110 + * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
45.111 + * as defined in section 3.3 of
45.112 + * <cite>The Java™ Language Specification</cite>
45.113 + * whereas the other constructor which takes a Reader does not have that limitation.
45.114 + *
45.115 + * @see ResourceBundle
45.116 + * @see ListResourceBundle
45.117 + * @see Properties
45.118 + * @since JDK1.1
45.119 + */
45.120 +public class PropertyResourceBundle extends ResourceBundle {
45.121 + /**
45.122 + * Creates a property resource bundle from an {@link java.io.InputStream
45.123 + * InputStream}. The property file read with this constructor
45.124 + * must be encoded in ISO-8859-1.
45.125 + *
45.126 + * @param stream an InputStream that represents a property file
45.127 + * to read from.
45.128 + * @throws IOException if an I/O error occurs
45.129 + * @throws NullPointerException if <code>stream</code> is null
45.130 + */
45.131 + public PropertyResourceBundle (InputStream stream) throws IOException {
45.132 + Properties properties = new Properties();
45.133 + properties.load(stream);
45.134 + lookup = new HashMap(properties);
45.135 + }
45.136 +
45.137 + /**
45.138 + * Creates a property resource bundle from a {@link java.io.Reader
45.139 + * Reader}. Unlike the constructor
45.140 + * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
45.141 + * there is no limitation as to the encoding of the input property file.
45.142 + *
45.143 + * @param reader a Reader that represents a property file to
45.144 + * read from.
45.145 + * @throws IOException if an I/O error occurs
45.146 + * @throws NullPointerException if <code>reader</code> is null
45.147 + * @since 1.6
45.148 + */
45.149 + public PropertyResourceBundle (Reader reader) throws IOException {
45.150 + Properties properties = new Properties();
45.151 + properties.load(reader);
45.152 + lookup = new HashMap(properties);
45.153 + }
45.154 +
45.155 + // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
45.156 + public Object handleGetObject(String key) {
45.157 + if (key == null) {
45.158 + throw new NullPointerException();
45.159 + }
45.160 + return lookup.get(key);
45.161 + }
45.162 +
45.163 + /**
45.164 + * Returns an <code>Enumeration</code> of the keys contained in
45.165 + * this <code>ResourceBundle</code> and its parent bundles.
45.166 + *
45.167 + * @return an <code>Enumeration</code> of the keys contained in
45.168 + * this <code>ResourceBundle</code> and its parent bundles.
45.169 + * @see #keySet()
45.170 + */
45.171 + public Enumeration<String> getKeys() {
45.172 + ResourceBundle parent = this.parent;
45.173 + return new ResourceBundleEnumeration(lookup.keySet(),
45.174 + (parent != null) ? parent.getKeys() : null);
45.175 + }
45.176 +
45.177 + /**
45.178 + * Returns a <code>Set</code> of the keys contained
45.179 + * <em>only</em> in this <code>ResourceBundle</code>.
45.180 + *
45.181 + * @return a <code>Set</code> of the keys contained only in this
45.182 + * <code>ResourceBundle</code>
45.183 + * @since 1.6
45.184 + * @see #keySet()
45.185 + */
45.186 + protected Set<String> handleKeySet() {
45.187 + return lookup.keySet();
45.188 + }
45.189 +
45.190 + // ==================privates====================
45.191 +
45.192 + private Map<String,Object> lookup;
45.193 +}
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/rt/emul/compact/src/main/java/java/util/ResourceBundle.java Thu Oct 03 15:40:35 2013 +0200
46.3 @@ -0,0 +1,2911 @@
46.4 +/*
46.5 + * Copyright (c) 1996, 2011, 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 - 1999 - 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 +import java.io.IOException;
46.47 +import java.io.InputStream;
46.48 +import java.lang.ref.ReferenceQueue;
46.49 +import java.lang.ref.SoftReference;
46.50 +import java.lang.ref.WeakReference;
46.51 +import java.net.JarURLConnection;
46.52 +import java.net.URL;
46.53 +import java.net.URLConnection;
46.54 +import java.security.AccessController;
46.55 +import java.security.PrivilegedAction;
46.56 +import java.security.PrivilegedActionException;
46.57 +import java.security.PrivilegedExceptionAction;
46.58 +import java.util.concurrent.ConcurrentHashMap;
46.59 +import java.util.concurrent.ConcurrentMap;
46.60 +import java.util.jar.JarEntry;
46.61 +
46.62 +import sun.util.locale.BaseLocale;
46.63 +import sun.util.locale.LocaleObjectCache;
46.64 +
46.65 +
46.66 +/**
46.67 + *
46.68 + * Resource bundles contain locale-specific objects. When your program needs a
46.69 + * locale-specific resource, a <code>String</code> for example, your program can
46.70 + * load it from the resource bundle that is appropriate for the current user's
46.71 + * locale. In this way, you can write program code that is largely independent
46.72 + * of the user's locale isolating most, if not all, of the locale-specific
46.73 + * information in resource bundles.
46.74 + *
46.75 + * <p>
46.76 + * This allows you to write programs that can:
46.77 + * <UL type=SQUARE>
46.78 + * <LI> be easily localized, or translated, into different languages
46.79 + * <LI> handle multiple locales at once
46.80 + * <LI> be easily modified later to support even more locales
46.81 + * </UL>
46.82 + *
46.83 + * <P>
46.84 + * Resource bundles belong to families whose members share a common base
46.85 + * name, but whose names also have additional components that identify
46.86 + * their locales. For example, the base name of a family of resource
46.87 + * bundles might be "MyResources". The family should have a default
46.88 + * resource bundle which simply has the same name as its family -
46.89 + * "MyResources" - and will be used as the bundle of last resort if a
46.90 + * specific locale is not supported. The family can then provide as
46.91 + * many locale-specific members as needed, for example a German one
46.92 + * named "MyResources_de".
46.93 + *
46.94 + * <P>
46.95 + * Each resource bundle in a family contains the same items, but the items have
46.96 + * been translated for the locale represented by that resource bundle.
46.97 + * For example, both "MyResources" and "MyResources_de" may have a
46.98 + * <code>String</code> that's used on a button for canceling operations.
46.99 + * In "MyResources" the <code>String</code> may contain "Cancel" and in
46.100 + * "MyResources_de" it may contain "Abbrechen".
46.101 + *
46.102 + * <P>
46.103 + * If there are different resources for different countries, you
46.104 + * can make specializations: for example, "MyResources_de_CH" contains objects for
46.105 + * the German language (de) in Switzerland (CH). If you want to only
46.106 + * modify some of the resources
46.107 + * in the specialization, you can do so.
46.108 + *
46.109 + * <P>
46.110 + * When your program needs a locale-specific object, it loads
46.111 + * the <code>ResourceBundle</code> class using the
46.112 + * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
46.113 + * method:
46.114 + * <blockquote>
46.115 + * <pre>
46.116 + * ResourceBundle myResources =
46.117 + * ResourceBundle.getBundle("MyResources", currentLocale);
46.118 + * </pre>
46.119 + * </blockquote>
46.120 + *
46.121 + * <P>
46.122 + * Resource bundles contain key/value pairs. The keys uniquely
46.123 + * identify a locale-specific object in the bundle. Here's an
46.124 + * example of a <code>ListResourceBundle</code> that contains
46.125 + * two key/value pairs:
46.126 + * <blockquote>
46.127 + * <pre>
46.128 + * public class MyResources extends ListResourceBundle {
46.129 + * protected Object[][] getContents() {
46.130 + * return new Object[][] {
46.131 + * // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
46.132 + * {"OkKey", "OK"},
46.133 + * {"CancelKey", "Cancel"},
46.134 + * // END OF MATERIAL TO LOCALIZE
46.135 + * };
46.136 + * }
46.137 + * }
46.138 + * </pre>
46.139 + * </blockquote>
46.140 + * Keys are always <code>String</code>s.
46.141 + * In this example, the keys are "OkKey" and "CancelKey".
46.142 + * In the above example, the values
46.143 + * are also <code>String</code>s--"OK" and "Cancel"--but
46.144 + * they don't have to be. The values can be any type of object.
46.145 + *
46.146 + * <P>
46.147 + * You retrieve an object from resource bundle using the appropriate
46.148 + * getter method. Because "OkKey" and "CancelKey"
46.149 + * are both strings, you would use <code>getString</code> to retrieve them:
46.150 + * <blockquote>
46.151 + * <pre>
46.152 + * button1 = new Button(myResources.getString("OkKey"));
46.153 + * button2 = new Button(myResources.getString("CancelKey"));
46.154 + * </pre>
46.155 + * </blockquote>
46.156 + * The getter methods all require the key as an argument and return
46.157 + * the object if found. If the object is not found, the getter method
46.158 + * throws a <code>MissingResourceException</code>.
46.159 + *
46.160 + * <P>
46.161 + * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
46.162 + * a method for getting string arrays, <code>getStringArray</code>,
46.163 + * as well as a generic <code>getObject</code> method for any other
46.164 + * type of object. When using <code>getObject</code>, you'll
46.165 + * have to cast the result to the appropriate type. For example:
46.166 + * <blockquote>
46.167 + * <pre>
46.168 + * int[] myIntegers = (int[]) myResources.getObject("intList");
46.169 + * </pre>
46.170 + * </blockquote>
46.171 + *
46.172 + * <P>
46.173 + * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
46.174 + * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
46.175 + * that provide a fairly simple way to create resources.
46.176 + * As you saw briefly in a previous example, <code>ListResourceBundle</code>
46.177 + * manages its resource as a list of key/value pairs.
46.178 + * <code>PropertyResourceBundle</code> uses a properties file to manage
46.179 + * its resources.
46.180 + *
46.181 + * <p>
46.182 + * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
46.183 + * do not suit your needs, you can write your own <code>ResourceBundle</code>
46.184 + * subclass. Your subclasses must override two methods: <code>handleGetObject</code>
46.185 + * and <code>getKeys()</code>.
46.186 + *
46.187 + * <h4>ResourceBundle.Control</h4>
46.188 + *
46.189 + * The {@link ResourceBundle.Control} class provides information necessary
46.190 + * to perform the bundle loading process by the <code>getBundle</code>
46.191 + * factory methods that take a <code>ResourceBundle.Control</code>
46.192 + * instance. You can implement your own subclass in order to enable
46.193 + * non-standard resource bundle formats, change the search strategy, or
46.194 + * define caching parameters. Refer to the descriptions of the class and the
46.195 + * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
46.196 + * factory method for details.
46.197 + *
46.198 + * <h4>Cache Management</h4>
46.199 + *
46.200 + * Resource bundle instances created by the <code>getBundle</code> factory
46.201 + * methods are cached by default, and the factory methods return the same
46.202 + * resource bundle instance multiple times if it has been
46.203 + * cached. <code>getBundle</code> clients may clear the cache, manage the
46.204 + * lifetime of cached resource bundle instances using time-to-live values,
46.205 + * or specify not to cache resource bundle instances. Refer to the
46.206 + * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
46.207 + * Control) <code>getBundle</code> factory method}, {@link
46.208 + * #clearCache(ClassLoader) clearCache}, {@link
46.209 + * Control#getTimeToLive(String, Locale)
46.210 + * ResourceBundle.Control.getTimeToLive}, and {@link
46.211 + * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
46.212 + * long) ResourceBundle.Control.needsReload} for details.
46.213 + *
46.214 + * <h4>Example</h4>
46.215 + *
46.216 + * The following is a very simple example of a <code>ResourceBundle</code>
46.217 + * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
46.218 + * resources you would probably use a <code>Map</code>).
46.219 + * Notice that you don't need to supply a value if
46.220 + * a "parent-level" <code>ResourceBundle</code> handles the same
46.221 + * key with the same value (as for the okKey below).
46.222 + * <blockquote>
46.223 + * <pre>
46.224 + * // default (English language, United States)
46.225 + * public class MyResources extends ResourceBundle {
46.226 + * public Object handleGetObject(String key) {
46.227 + * if (key.equals("okKey")) return "Ok";
46.228 + * if (key.equals("cancelKey")) return "Cancel";
46.229 + * return null;
46.230 + * }
46.231 + *
46.232 + * public Enumeration<String> getKeys() {
46.233 + * return Collections.enumeration(keySet());
46.234 + * }
46.235 + *
46.236 + * // Overrides handleKeySet() so that the getKeys() implementation
46.237 + * // can rely on the keySet() value.
46.238 + * protected Set<String> handleKeySet() {
46.239 + * return new HashSet<String>(Arrays.asList("okKey", "cancelKey"));
46.240 + * }
46.241 + * }
46.242 + *
46.243 + * // German language
46.244 + * public class MyResources_de extends MyResources {
46.245 + * public Object handleGetObject(String key) {
46.246 + * // don't need okKey, since parent level handles it.
46.247 + * if (key.equals("cancelKey")) return "Abbrechen";
46.248 + * return null;
46.249 + * }
46.250 + *
46.251 + * protected Set<String> handleKeySet() {
46.252 + * return new HashSet<String>(Arrays.asList("cancelKey"));
46.253 + * }
46.254 + * }
46.255 + * </pre>
46.256 + * </blockquote>
46.257 + * You do not have to restrict yourself to using a single family of
46.258 + * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
46.259 + * exception messages, <code>ExceptionResources</code>
46.260 + * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
46.261 + * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
46.262 + * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
46.263 + *
46.264 + * @see ListResourceBundle
46.265 + * @see PropertyResourceBundle
46.266 + * @see MissingResourceException
46.267 + * @since JDK1.1
46.268 + */
46.269 +public abstract class ResourceBundle {
46.270 +
46.271 + /** initial size of the bundle cache */
46.272 + private static final int INITIAL_CACHE_SIZE = 32;
46.273 +
46.274 + /** constant indicating that no resource bundle exists */
46.275 + private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
46.276 + public Enumeration<String> getKeys() { return null; }
46.277 + protected Object handleGetObject(String key) { return null; }
46.278 + public String toString() { return "NONEXISTENT_BUNDLE"; }
46.279 + };
46.280 +
46.281 +
46.282 + /**
46.283 + * The cache is a map from cache keys (with bundle base name, locale, and
46.284 + * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
46.285 + * BundleReference.
46.286 + *
46.287 + * The cache is a ConcurrentMap, allowing the cache to be searched
46.288 + * concurrently by multiple threads. This will also allow the cache keys
46.289 + * to be reclaimed along with the ClassLoaders they reference.
46.290 + *
46.291 + * This variable would be better named "cache", but we keep the old
46.292 + * name for compatibility with some workarounds for bug 4212439.
46.293 + */
46.294 + private static final ConcurrentMap<CacheKey, BundleReference> cacheList
46.295 + = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
46.296 +
46.297 + /**
46.298 + * Queue for reference objects referring to class loaders or bundles.
46.299 + */
46.300 + private static final ReferenceQueue referenceQueue = new ReferenceQueue();
46.301 +
46.302 + /**
46.303 + * The parent bundle of this bundle.
46.304 + * The parent bundle is searched by {@link #getObject getObject}
46.305 + * when this bundle does not contain a particular resource.
46.306 + */
46.307 + protected ResourceBundle parent = null;
46.308 +
46.309 + /**
46.310 + * The locale for this bundle.
46.311 + */
46.312 + private Locale locale = null;
46.313 +
46.314 + /**
46.315 + * The base bundle name for this bundle.
46.316 + */
46.317 + private String name;
46.318 +
46.319 + /**
46.320 + * The flag indicating this bundle has expired in the cache.
46.321 + */
46.322 + private volatile boolean expired;
46.323 +
46.324 + /**
46.325 + * The back link to the cache key. null if this bundle isn't in
46.326 + * the cache (yet) or has expired.
46.327 + */
46.328 + private volatile CacheKey cacheKey;
46.329 +
46.330 + /**
46.331 + * A Set of the keys contained only in this ResourceBundle.
46.332 + */
46.333 + private volatile Set<String> keySet;
46.334 +
46.335 + /**
46.336 + * Sole constructor. (For invocation by subclass constructors, typically
46.337 + * implicit.)
46.338 + */
46.339 + public ResourceBundle() {
46.340 + }
46.341 +
46.342 + /**
46.343 + * Gets a string for the given key from this resource bundle or one of its parents.
46.344 + * Calling this method is equivalent to calling
46.345 + * <blockquote>
46.346 + * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
46.347 + * </blockquote>
46.348 + *
46.349 + * @param key the key for the desired string
46.350 + * @exception NullPointerException if <code>key</code> is <code>null</code>
46.351 + * @exception MissingResourceException if no object for the given key can be found
46.352 + * @exception ClassCastException if the object found for the given key is not a string
46.353 + * @return the string for the given key
46.354 + */
46.355 + public final String getString(String key) {
46.356 + return (String) getObject(key);
46.357 + }
46.358 +
46.359 + /**
46.360 + * Gets a string array for the given key from this resource bundle or one of its parents.
46.361 + * Calling this method is equivalent to calling
46.362 + * <blockquote>
46.363 + * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
46.364 + * </blockquote>
46.365 + *
46.366 + * @param key the key for the desired string array
46.367 + * @exception NullPointerException if <code>key</code> is <code>null</code>
46.368 + * @exception MissingResourceException if no object for the given key can be found
46.369 + * @exception ClassCastException if the object found for the given key is not a string array
46.370 + * @return the string array for the given key
46.371 + */
46.372 + public final String[] getStringArray(String key) {
46.373 + return (String[]) getObject(key);
46.374 + }
46.375 +
46.376 + /**
46.377 + * Gets an object for the given key from this resource bundle or one of its parents.
46.378 + * This method first tries to obtain the object from this resource bundle using
46.379 + * {@link #handleGetObject(java.lang.String) handleGetObject}.
46.380 + * If not successful, and the parent resource bundle is not null,
46.381 + * it calls the parent's <code>getObject</code> method.
46.382 + * If still not successful, it throws a MissingResourceException.
46.383 + *
46.384 + * @param key the key for the desired object
46.385 + * @exception NullPointerException if <code>key</code> is <code>null</code>
46.386 + * @exception MissingResourceException if no object for the given key can be found
46.387 + * @return the object for the given key
46.388 + */
46.389 + public final Object getObject(String key) {
46.390 + Object obj = handleGetObject(key);
46.391 + if (obj == null) {
46.392 + if (parent != null) {
46.393 + obj = parent.getObject(key);
46.394 + }
46.395 + if (obj == null)
46.396 + throw new MissingResourceException("Can't find resource for bundle "
46.397 + +this.getClass().getName()
46.398 + +", key "+key,
46.399 + this.getClass().getName(),
46.400 + key);
46.401 + }
46.402 + return obj;
46.403 + }
46.404 +
46.405 + /**
46.406 + * Returns the locale of this resource bundle. This method can be used after a
46.407 + * call to getBundle() to determine whether the resource bundle returned really
46.408 + * corresponds to the requested locale or is a fallback.
46.409 + *
46.410 + * @return the locale of this resource bundle
46.411 + */
46.412 + public Locale getLocale() {
46.413 + return locale;
46.414 + }
46.415 +
46.416 + /*
46.417 + * Automatic determination of the ClassLoader to be used to load
46.418 + * resources on behalf of the client. N.B. The client is getLoader's
46.419 + * caller's caller.
46.420 + */
46.421 + private static ClassLoader getLoader() {
46.422 + Class[] stack = getClassContext();
46.423 + /* Magic number 2 identifies our caller's caller */
46.424 + Class c = stack[2];
46.425 + ClassLoader cl = (c == null) ? null : c.getClassLoader();
46.426 + if (cl == null) {
46.427 + // When the caller's loader is the boot class loader, cl is null
46.428 + // here. In that case, ClassLoader.getSystemClassLoader() may
46.429 + // return the same class loader that the application is
46.430 + // using. We therefore use a wrapper ClassLoader to create a
46.431 + // separate scope for bundles loaded on behalf of the Java
46.432 + // runtime so that these bundles cannot be returned from the
46.433 + // cache to the application (5048280).
46.434 + cl = RBClassLoader.INSTANCE;
46.435 + }
46.436 + return cl;
46.437 + }
46.438 +
46.439 + private static native Class[] getClassContext();
46.440 +
46.441 + /**
46.442 + * A wrapper of ClassLoader.getSystemClassLoader().
46.443 + */
46.444 + private static class RBClassLoader extends ClassLoader {
46.445 + private static final RBClassLoader INSTANCE = AccessController.doPrivileged(
46.446 + new PrivilegedAction<RBClassLoader>() {
46.447 + public RBClassLoader run() {
46.448 + return new RBClassLoader();
46.449 + }
46.450 + });
46.451 + private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
46.452 +
46.453 + private RBClassLoader() {
46.454 + }
46.455 + public Class<?> loadClass(String name) throws ClassNotFoundException {
46.456 + if (loader != null) {
46.457 + return loader.loadClass(name);
46.458 + }
46.459 + return Class.forName(name);
46.460 + }
46.461 + public URL getResource(String name) {
46.462 + if (loader != null) {
46.463 + return loader.getResource(name);
46.464 + }
46.465 + return ClassLoader.getSystemResource(name);
46.466 + }
46.467 + public InputStream getResourceAsStream(String name) {
46.468 + if (loader != null) {
46.469 + return loader.getResourceAsStream(name);
46.470 + }
46.471 + return ClassLoader.getSystemResourceAsStream(name);
46.472 + }
46.473 + }
46.474 +
46.475 + /**
46.476 + * Sets the parent bundle of this bundle.
46.477 + * The parent bundle is searched by {@link #getObject getObject}
46.478 + * when this bundle does not contain a particular resource.
46.479 + *
46.480 + * @param parent this bundle's parent bundle.
46.481 + */
46.482 + protected void setParent(ResourceBundle parent) {
46.483 + assert parent != NONEXISTENT_BUNDLE;
46.484 + this.parent = parent;
46.485 + }
46.486 +
46.487 + /**
46.488 + * Key used for cached resource bundles. The key checks the base
46.489 + * name, the locale, and the class loader to determine if the
46.490 + * resource is a match to the requested one. The loader may be
46.491 + * null, but the base name and the locale must have a non-null
46.492 + * value.
46.493 + */
46.494 + private static final class CacheKey implements Cloneable {
46.495 + // These three are the actual keys for lookup in Map.
46.496 + private String name;
46.497 + private Locale locale;
46.498 + private LoaderReference loaderRef;
46.499 +
46.500 + // bundle format which is necessary for calling
46.501 + // Control.needsReload().
46.502 + private String format;
46.503 +
46.504 + // These time values are in CacheKey so that NONEXISTENT_BUNDLE
46.505 + // doesn't need to be cloned for caching.
46.506 +
46.507 + // The time when the bundle has been loaded
46.508 + private volatile long loadTime;
46.509 +
46.510 + // The time when the bundle expires in the cache, or either
46.511 + // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
46.512 + private volatile long expirationTime;
46.513 +
46.514 + // Placeholder for an error report by a Throwable
46.515 + private Throwable cause;
46.516 +
46.517 + // Hash code value cache to avoid recalculating the hash code
46.518 + // of this instance.
46.519 + private int hashCodeCache;
46.520 +
46.521 + CacheKey(String baseName, Locale locale, ClassLoader loader) {
46.522 + this.name = baseName;
46.523 + this.locale = locale;
46.524 + if (loader == null) {
46.525 + this.loaderRef = null;
46.526 + } else {
46.527 + loaderRef = new LoaderReference(loader, referenceQueue, this);
46.528 + }
46.529 + calculateHashCode();
46.530 + }
46.531 +
46.532 + String getName() {
46.533 + return name;
46.534 + }
46.535 +
46.536 + CacheKey setName(String baseName) {
46.537 + if (!this.name.equals(baseName)) {
46.538 + this.name = baseName;
46.539 + calculateHashCode();
46.540 + }
46.541 + return this;
46.542 + }
46.543 +
46.544 + Locale getLocale() {
46.545 + return locale;
46.546 + }
46.547 +
46.548 + CacheKey setLocale(Locale locale) {
46.549 + if (!this.locale.equals(locale)) {
46.550 + this.locale = locale;
46.551 + calculateHashCode();
46.552 + }
46.553 + return this;
46.554 + }
46.555 +
46.556 + ClassLoader getLoader() {
46.557 + return (loaderRef != null) ? loaderRef.get() : null;
46.558 + }
46.559 +
46.560 + public boolean equals(Object other) {
46.561 + if (this == other) {
46.562 + return true;
46.563 + }
46.564 + try {
46.565 + final CacheKey otherEntry = (CacheKey)other;
46.566 + //quick check to see if they are not equal
46.567 + if (hashCodeCache != otherEntry.hashCodeCache) {
46.568 + return false;
46.569 + }
46.570 + //are the names the same?
46.571 + if (!name.equals(otherEntry.name)) {
46.572 + return false;
46.573 + }
46.574 + // are the locales the same?
46.575 + if (!locale.equals(otherEntry.locale)) {
46.576 + return false;
46.577 + }
46.578 + //are refs (both non-null) or (both null)?
46.579 + if (loaderRef == null) {
46.580 + return otherEntry.loaderRef == null;
46.581 + }
46.582 + ClassLoader loader = loaderRef.get();
46.583 + return (otherEntry.loaderRef != null)
46.584 + // with a null reference we can no longer find
46.585 + // out which class loader was referenced; so
46.586 + // treat it as unequal
46.587 + && (loader != null)
46.588 + && (loader == otherEntry.loaderRef.get());
46.589 + } catch (NullPointerException e) {
46.590 + } catch (ClassCastException e) {
46.591 + }
46.592 + return false;
46.593 + }
46.594 +
46.595 + public int hashCode() {
46.596 + return hashCodeCache;
46.597 + }
46.598 +
46.599 + private void calculateHashCode() {
46.600 + hashCodeCache = name.hashCode() << 3;
46.601 + hashCodeCache ^= locale.hashCode();
46.602 + ClassLoader loader = getLoader();
46.603 + if (loader != null) {
46.604 + hashCodeCache ^= loader.hashCode();
46.605 + }
46.606 + }
46.607 +
46.608 + public Object clone() {
46.609 + try {
46.610 + CacheKey clone = (CacheKey) super.clone();
46.611 + if (loaderRef != null) {
46.612 + clone.loaderRef = new LoaderReference(loaderRef.get(),
46.613 + referenceQueue, clone);
46.614 + }
46.615 + // Clear the reference to a Throwable
46.616 + clone.cause = null;
46.617 + return clone;
46.618 + } catch (CloneNotSupportedException e) {
46.619 + //this should never happen
46.620 + throw new InternalError();
46.621 + }
46.622 + }
46.623 +
46.624 + String getFormat() {
46.625 + return format;
46.626 + }
46.627 +
46.628 + void setFormat(String format) {
46.629 + this.format = format;
46.630 + }
46.631 +
46.632 + private void setCause(Throwable cause) {
46.633 + if (this.cause == null) {
46.634 + this.cause = cause;
46.635 + } else {
46.636 + // Override the cause if the previous one is
46.637 + // ClassNotFoundException.
46.638 + if (this.cause instanceof ClassNotFoundException) {
46.639 + this.cause = cause;
46.640 + }
46.641 + }
46.642 + }
46.643 +
46.644 + private Throwable getCause() {
46.645 + return cause;
46.646 + }
46.647 +
46.648 + public String toString() {
46.649 + String l = locale.toString();
46.650 + if (l.length() == 0) {
46.651 + if (locale.getVariant().length() != 0) {
46.652 + l = "__" + locale.getVariant();
46.653 + } else {
46.654 + l = "\"\"";
46.655 + }
46.656 + }
46.657 + return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader()
46.658 + + "(format=" + format + ")]";
46.659 + }
46.660 + }
46.661 +
46.662 + /**
46.663 + * The common interface to get a CacheKey in LoaderReference and
46.664 + * BundleReference.
46.665 + */
46.666 + private static interface CacheKeyReference {
46.667 + public CacheKey getCacheKey();
46.668 + }
46.669 +
46.670 + /**
46.671 + * References to class loaders are weak references, so that they can be
46.672 + * garbage collected when nobody else is using them. The ResourceBundle
46.673 + * class has no reason to keep class loaders alive.
46.674 + */
46.675 + private static final class LoaderReference extends WeakReference<ClassLoader>
46.676 + implements CacheKeyReference {
46.677 + private CacheKey cacheKey;
46.678 +
46.679 + LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) {
46.680 + super(referent, q);
46.681 + cacheKey = key;
46.682 + }
46.683 +
46.684 + public CacheKey getCacheKey() {
46.685 + return cacheKey;
46.686 + }
46.687 + }
46.688 +
46.689 + /**
46.690 + * References to bundles are soft references so that they can be garbage
46.691 + * collected when they have no hard references.
46.692 + */
46.693 + private static final class BundleReference extends SoftReference<ResourceBundle>
46.694 + implements CacheKeyReference {
46.695 + private CacheKey cacheKey;
46.696 +
46.697 + BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) {
46.698 + super(referent, q);
46.699 + cacheKey = key;
46.700 + }
46.701 +
46.702 + public CacheKey getCacheKey() {
46.703 + return cacheKey;
46.704 + }
46.705 + }
46.706 +
46.707 + /**
46.708 + * Gets a resource bundle using the specified base name, the default locale,
46.709 + * and the caller's class loader. Calling this method is equivalent to calling
46.710 + * <blockquote>
46.711 + * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
46.712 + * </blockquote>
46.713 + * except that <code>getClassLoader()</code> is run with the security
46.714 + * privileges of <code>ResourceBundle</code>.
46.715 + * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
46.716 + * for a complete description of the search and instantiation strategy.
46.717 + *
46.718 + * @param baseName the base name of the resource bundle, a fully qualified class name
46.719 + * @exception java.lang.NullPointerException
46.720 + * if <code>baseName</code> is <code>null</code>
46.721 + * @exception MissingResourceException
46.722 + * if no resource bundle for the specified base name can be found
46.723 + * @return a resource bundle for the given base name and the default locale
46.724 + */
46.725 + public static final ResourceBundle getBundle(String baseName)
46.726 + {
46.727 + return getBundleImpl(baseName, Locale.getDefault(),
46.728 + /* must determine loader here, else we break stack invariant */
46.729 + getLoader(),
46.730 + Control.INSTANCE);
46.731 + }
46.732 +
46.733 + /**
46.734 + * Returns a resource bundle using the specified base name, the
46.735 + * default locale and the specified control. Calling this method
46.736 + * is equivalent to calling
46.737 + * <pre>
46.738 + * getBundle(baseName, Locale.getDefault(),
46.739 + * this.getClass().getClassLoader(), control),
46.740 + * </pre>
46.741 + * except that <code>getClassLoader()</code> is run with the security
46.742 + * privileges of <code>ResourceBundle</code>. See {@link
46.743 + * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
46.744 + * complete description of the resource bundle loading process with a
46.745 + * <code>ResourceBundle.Control</code>.
46.746 + *
46.747 + * @param baseName
46.748 + * the base name of the resource bundle, a fully qualified class
46.749 + * name
46.750 + * @param control
46.751 + * the control which gives information for the resource bundle
46.752 + * loading process
46.753 + * @return a resource bundle for the given base name and the default
46.754 + * locale
46.755 + * @exception NullPointerException
46.756 + * if <code>baseName</code> or <code>control</code> is
46.757 + * <code>null</code>
46.758 + * @exception MissingResourceException
46.759 + * if no resource bundle for the specified base name can be found
46.760 + * @exception IllegalArgumentException
46.761 + * if the given <code>control</code> doesn't perform properly
46.762 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
46.763 + * Note that validation of <code>control</code> is performed as
46.764 + * needed.
46.765 + * @since 1.6
46.766 + */
46.767 + public static final ResourceBundle getBundle(String baseName,
46.768 + Control control) {
46.769 + return getBundleImpl(baseName, Locale.getDefault(),
46.770 + /* must determine loader here, else we break stack invariant */
46.771 + getLoader(),
46.772 + control);
46.773 + }
46.774 +
46.775 + /**
46.776 + * Gets a resource bundle using the specified base name and locale,
46.777 + * and the caller's class loader. Calling this method is equivalent to calling
46.778 + * <blockquote>
46.779 + * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
46.780 + * </blockquote>
46.781 + * except that <code>getClassLoader()</code> is run with the security
46.782 + * privileges of <code>ResourceBundle</code>.
46.783 + * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
46.784 + * for a complete description of the search and instantiation strategy.
46.785 + *
46.786 + * @param baseName
46.787 + * the base name of the resource bundle, a fully qualified class name
46.788 + * @param locale
46.789 + * the locale for which a resource bundle is desired
46.790 + * @exception NullPointerException
46.791 + * if <code>baseName</code> or <code>locale</code> is <code>null</code>
46.792 + * @exception MissingResourceException
46.793 + * if no resource bundle for the specified base name can be found
46.794 + * @return a resource bundle for the given base name and locale
46.795 + */
46.796 + public static final ResourceBundle getBundle(String baseName,
46.797 + Locale locale)
46.798 + {
46.799 + return getBundleImpl(baseName, locale,
46.800 + /* must determine loader here, else we break stack invariant */
46.801 + getLoader(),
46.802 + Control.INSTANCE);
46.803 + }
46.804 +
46.805 + /**
46.806 + * Returns a resource bundle using the specified base name, target
46.807 + * locale and control, and the caller's class loader. Calling this
46.808 + * method is equivalent to calling
46.809 + * <pre>
46.810 + * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
46.811 + * control),
46.812 + * </pre>
46.813 + * except that <code>getClassLoader()</code> is run with the security
46.814 + * privileges of <code>ResourceBundle</code>. See {@link
46.815 + * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
46.816 + * complete description of the resource bundle loading process with a
46.817 + * <code>ResourceBundle.Control</code>.
46.818 + *
46.819 + * @param baseName
46.820 + * the base name of the resource bundle, a fully qualified
46.821 + * class name
46.822 + * @param targetLocale
46.823 + * the locale for which a resource bundle is desired
46.824 + * @param control
46.825 + * the control which gives information for the resource
46.826 + * bundle loading process
46.827 + * @return a resource bundle for the given base name and a
46.828 + * <code>Locale</code> in <code>locales</code>
46.829 + * @exception NullPointerException
46.830 + * if <code>baseName</code>, <code>locales</code> or
46.831 + * <code>control</code> is <code>null</code>
46.832 + * @exception MissingResourceException
46.833 + * if no resource bundle for the specified base name in any
46.834 + * of the <code>locales</code> can be found.
46.835 + * @exception IllegalArgumentException
46.836 + * if the given <code>control</code> doesn't perform properly
46.837 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
46.838 + * Note that validation of <code>control</code> is performed as
46.839 + * needed.
46.840 + * @since 1.6
46.841 + */
46.842 + public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
46.843 + Control control) {
46.844 + return getBundleImpl(baseName, targetLocale,
46.845 + /* must determine loader here, else we break stack invariant */
46.846 + getLoader(),
46.847 + control);
46.848 + }
46.849 +
46.850 + /**
46.851 + * Gets a resource bundle using the specified base name, locale, and class
46.852 + * loader.
46.853 + *
46.854 + * <p><a name="default_behavior"/>This method behaves the same as calling
46.855 + * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
46.856 + * default instance of {@link Control}. The following describes this behavior.
46.857 + *
46.858 + * <p><code>getBundle</code> uses the base name, the specified locale, and
46.859 + * the default locale (obtained from {@link java.util.Locale#getDefault()
46.860 + * Locale.getDefault}) to generate a sequence of <a
46.861 + * name="candidates"><em>candidate bundle names</em></a>. If the specified
46.862 + * locale's language, script, country, and variant are all empty strings,
46.863 + * then the base name is the only candidate bundle name. Otherwise, a list
46.864 + * of candidate locales is generated from the attribute values of the
46.865 + * specified locale (language, script, country and variant) and appended to
46.866 + * the base name. Typically, this will look like the following:
46.867 + *
46.868 + * <pre>
46.869 + * baseName + "_" + language + "_" + script + "_" + country + "_" + variant
46.870 + * baseName + "_" + language + "_" + script + "_" + country
46.871 + * baseName + "_" + language + "_" + script
46.872 + * baseName + "_" + language + "_" + country + "_" + variant
46.873 + * baseName + "_" + language + "_" + country
46.874 + * baseName + "_" + language
46.875 + * </pre>
46.876 + *
46.877 + * <p>Candidate bundle names where the final component is an empty string
46.878 + * are omitted, along with the underscore. For example, if country is an
46.879 + * empty string, the second and the fifth candidate bundle names above
46.880 + * would be omitted. Also, if script is an empty string, the candidate names
46.881 + * including script are omitted. For example, a locale with language "de"
46.882 + * and variant "JAVA" will produce candidate names with base name
46.883 + * "MyResource" below.
46.884 + *
46.885 + * <pre>
46.886 + * MyResource_de__JAVA
46.887 + * MyResource_de
46.888 + * </pre>
46.889 + *
46.890 + * In the case that the variant contains one or more underscores ('_'), a
46.891 + * sequence of bundle names generated by truncating the last underscore and
46.892 + * the part following it is inserted after a candidate bundle name with the
46.893 + * original variant. For example, for a locale with language "en", script
46.894 + * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
46.895 + * "MyResource", the list of candidate bundle names below is generated:
46.896 + *
46.897 + * <pre>
46.898 + * MyResource_en_Latn_US_WINDOWS_VISTA
46.899 + * MyResource_en_Latn_US_WINDOWS
46.900 + * MyResource_en_Latn_US
46.901 + * MyResource_en_Latn
46.902 + * MyResource_en_US_WINDOWS_VISTA
46.903 + * MyResource_en_US_WINDOWS
46.904 + * MyResource_en_US
46.905 + * MyResource_en
46.906 + * </pre>
46.907 + *
46.908 + * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
46.909 + * candidate bundle names contains extra names, or the order of bundle names
46.910 + * is slightly modified. See the description of the default implementation
46.911 + * of {@link Control#getCandidateLocales(String, Locale)
46.912 + * getCandidateLocales} for details.</blockquote>
46.913 + *
46.914 + * <p><code>getBundle</code> then iterates over the candidate bundle names
46.915 + * to find the first one for which it can <em>instantiate</em> an actual
46.916 + * resource bundle. It uses the default controls' {@link Control#getFormats
46.917 + * getFormats} method, which generates two bundle names for each generated
46.918 + * name, the first a class name and the second a properties file name. For
46.919 + * each candidate bundle name, it attempts to create a resource bundle:
46.920 + *
46.921 + * <ul><li>First, it attempts to load a class using the generated class name.
46.922 + * If such a class can be found and loaded using the specified class
46.923 + * loader, is assignment compatible with ResourceBundle, is accessible from
46.924 + * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
46.925 + * new instance of this class and uses it as the <em>result resource
46.926 + * bundle</em>.
46.927 + *
46.928 + * <li>Otherwise, <code>getBundle</code> attempts to locate a property
46.929 + * resource file using the generated properties file name. It generates a
46.930 + * path name from the candidate bundle name by replacing all "." characters
46.931 + * with "/" and appending the string ".properties". It attempts to find a
46.932 + * "resource" with this name using {@link
46.933 + * java.lang.ClassLoader#getResource(java.lang.String)
46.934 + * ClassLoader.getResource}. (Note that a "resource" in the sense of
46.935 + * <code>getResource</code> has nothing to do with the contents of a
46.936 + * resource bundle, it is just a container of data, such as a file.) If it
46.937 + * finds a "resource", it attempts to create a new {@link
46.938 + * PropertyResourceBundle} instance from its contents. If successful, this
46.939 + * instance becomes the <em>result resource bundle</em>. </ul>
46.940 + *
46.941 + * <p>This continues until a result resource bundle is instantiated or the
46.942 + * list of candidate bundle names is exhausted. If no matching resource
46.943 + * bundle is found, the default control's {@link Control#getFallbackLocale
46.944 + * getFallbackLocale} method is called, which returns the current default
46.945 + * locale. A new sequence of candidate locale names is generated using this
46.946 + * locale and and searched again, as above.
46.947 + *
46.948 + * <p>If still no result bundle is found, the base name alone is looked up. If
46.949 + * this still fails, a <code>MissingResourceException</code> is thrown.
46.950 + *
46.951 + * <p><a name="parent_chain"/> Once a result resource bundle has been found,
46.952 + * its <em>parent chain</em> is instantiated. If the result bundle already
46.953 + * has a parent (perhaps because it was returned from a cache) the chain is
46.954 + * complete.
46.955 + *
46.956 + * <p>Otherwise, <code>getBundle</code> examines the remainder of the
46.957 + * candidate locale list that was used during the pass that generated the
46.958 + * result resource bundle. (As before, candidate bundle names where the
46.959 + * final component is an empty string are omitted.) When it comes to the
46.960 + * end of the candidate list, it tries the plain bundle name. With each of the
46.961 + * candidate bundle names it attempts to instantiate a resource bundle (first
46.962 + * looking for a class and then a properties file, as described above).
46.963 + *
46.964 + * <p>Whenever it succeeds, it calls the previously instantiated resource
46.965 + * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
46.966 + * with the new resource bundle. This continues until the list of names
46.967 + * is exhausted or the current bundle already has a non-null parent.
46.968 + *
46.969 + * <p>Once the parent chain is complete, the bundle is returned.
46.970 + *
46.971 + * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
46.972 + * bundles and might return the same resource bundle instance multiple times.
46.973 + *
46.974 + * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
46.975 + * qualified class name. However, for compatibility with earlier versions,
46.976 + * Sun's Java SE Runtime Environments do not verify this, and so it is
46.977 + * possible to access <code>PropertyResourceBundle</code>s by specifying a
46.978 + * path name (using "/") instead of a fully qualified class name (using
46.979 + * ".").
46.980 + *
46.981 + * <p><a name="default_behavior_example"/>
46.982 + * <strong>Example:</strong>
46.983 + * <p>
46.984 + * The following class and property files are provided:
46.985 + * <pre>
46.986 + * MyResources.class
46.987 + * MyResources.properties
46.988 + * MyResources_fr.properties
46.989 + * MyResources_fr_CH.class
46.990 + * MyResources_fr_CH.properties
46.991 + * MyResources_en.properties
46.992 + * MyResources_es_ES.class
46.993 + * </pre>
46.994 + *
46.995 + * The contents of all files are valid (that is, public non-abstract
46.996 + * subclasses of <code>ResourceBundle</code> for the ".class" files,
46.997 + * syntactically correct ".properties" files). The default locale is
46.998 + * <code>Locale("en", "GB")</code>.
46.999 + *
46.1000 + * <p>Calling <code>getBundle</code> with the locale arguments below will
46.1001 + * instantiate resource bundles as follows:
46.1002 + *
46.1003 + * <table>
46.1004 + * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
46.1005 + * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
46.1006 + * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
46.1007 + * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
46.1008 + * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
46.1009 + * </table>
46.1010 + *
46.1011 + * <p>The file MyResources_fr_CH.properties is never used because it is
46.1012 + * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
46.1013 + * is also hidden by MyResources.class.
46.1014 + *
46.1015 + * @param baseName the base name of the resource bundle, a fully qualified class name
46.1016 + * @param locale the locale for which a resource bundle is desired
46.1017 + * @param loader the class loader from which to load the resource bundle
46.1018 + * @return a resource bundle for the given base name and locale
46.1019 + * @exception java.lang.NullPointerException
46.1020 + * if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
46.1021 + * @exception MissingResourceException
46.1022 + * if no resource bundle for the specified base name can be found
46.1023 + * @since 1.2
46.1024 + */
46.1025 + public static ResourceBundle getBundle(String baseName, Locale locale,
46.1026 + ClassLoader loader)
46.1027 + {
46.1028 + if (loader == null) {
46.1029 + throw new NullPointerException();
46.1030 + }
46.1031 + return getBundleImpl(baseName, locale, loader, Control.INSTANCE);
46.1032 + }
46.1033 +
46.1034 + /**
46.1035 + * Returns a resource bundle using the specified base name, target
46.1036 + * locale, class loader and control. Unlike the {@linkplain
46.1037 + * #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
46.1038 + * factory methods with no <code>control</code> argument}, the given
46.1039 + * <code>control</code> specifies how to locate and instantiate resource
46.1040 + * bundles. Conceptually, the bundle loading process with the given
46.1041 + * <code>control</code> is performed in the following steps.
46.1042 + *
46.1043 + * <p>
46.1044 + * <ol>
46.1045 + * <li>This factory method looks up the resource bundle in the cache for
46.1046 + * the specified <code>baseName</code>, <code>targetLocale</code> and
46.1047 + * <code>loader</code>. If the requested resource bundle instance is
46.1048 + * found in the cache and the time-to-live periods of the instance and
46.1049 + * all of its parent instances have not expired, the instance is returned
46.1050 + * to the caller. Otherwise, this factory method proceeds with the
46.1051 + * loading process below.</li>
46.1052 + *
46.1053 + * <li>The {@link ResourceBundle.Control#getFormats(String)
46.1054 + * control.getFormats} method is called to get resource bundle formats
46.1055 + * to produce bundle or resource names. The strings
46.1056 + * <code>"java.class"</code> and <code>"java.properties"</code>
46.1057 + * designate class-based and {@linkplain PropertyResourceBundle
46.1058 + * property}-based resource bundles, respectively. Other strings
46.1059 + * starting with <code>"java."</code> are reserved for future extensions
46.1060 + * and must not be used for application-defined formats. Other strings
46.1061 + * designate application-defined formats.</li>
46.1062 + *
46.1063 + * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
46.1064 + * Locale) control.getCandidateLocales} method is called with the target
46.1065 + * locale to get a list of <em>candidate <code>Locale</code>s</em> for
46.1066 + * which resource bundles are searched.</li>
46.1067 + *
46.1068 + * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
46.1069 + * String, ClassLoader, boolean) control.newBundle} method is called to
46.1070 + * instantiate a <code>ResourceBundle</code> for the base bundle name, a
46.1071 + * candidate locale, and a format. (Refer to the note on the cache
46.1072 + * lookup below.) This step is iterated over all combinations of the
46.1073 + * candidate locales and formats until the <code>newBundle</code> method
46.1074 + * returns a <code>ResourceBundle</code> instance or the iteration has
46.1075 + * used up all the combinations. For example, if the candidate locales
46.1076 + * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
46.1077 + * <code>Locale("")</code> and the formats are <code>"java.class"</code>
46.1078 + * and <code>"java.properties"</code>, then the following is the
46.1079 + * sequence of locale-format combinations to be used to call
46.1080 + * <code>control.newBundle</code>.
46.1081 + *
46.1082 + * <table style="width: 50%; text-align: left; margin-left: 40px;"
46.1083 + * border="0" cellpadding="2" cellspacing="2">
46.1084 + * <tbody><code>
46.1085 + * <tr>
46.1086 + * <td
46.1087 + * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br>
46.1088 + * </td>
46.1089 + * <td
46.1090 + * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br>
46.1091 + * </td>
46.1092 + * </tr>
46.1093 + * <tr>
46.1094 + * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br>
46.1095 + * </td>
46.1096 + * <td style="vertical-align: top; width: 50%;">java.class<br>
46.1097 + * </td>
46.1098 + * </tr>
46.1099 + * <tr>
46.1100 + * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td>
46.1101 + * <td style="vertical-align: top; width: 50%;">java.properties<br>
46.1102 + * </td>
46.1103 + * </tr>
46.1104 + * <tr>
46.1105 + * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
46.1106 + * <td style="vertical-align: top; width: 50%;">java.class</td>
46.1107 + * </tr>
46.1108 + * <tr>
46.1109 + * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
46.1110 + * <td style="vertical-align: top; width: 50%;">java.properties</td>
46.1111 + * </tr>
46.1112 + * <tr>
46.1113 + * <td style="vertical-align: top; width: 50%;">Locale("")<br>
46.1114 + * </td>
46.1115 + * <td style="vertical-align: top; width: 50%;">java.class</td>
46.1116 + * </tr>
46.1117 + * <tr>
46.1118 + * <td style="vertical-align: top; width: 50%;">Locale("")</td>
46.1119 + * <td style="vertical-align: top; width: 50%;">java.properties</td>
46.1120 + * </tr>
46.1121 + * </code></tbody>
46.1122 + * </table>
46.1123 + * </li>
46.1124 + *
46.1125 + * <li>If the previous step has found no resource bundle, proceed to
46.1126 + * Step 6. If a bundle has been found that is a base bundle (a bundle
46.1127 + * for <code>Locale("")</code>), and the candidate locale list only contained
46.1128 + * <code>Locale("")</code>, return the bundle to the caller. If a bundle
46.1129 + * has been found that is a base bundle, but the candidate locale list
46.1130 + * contained locales other than Locale(""), put the bundle on hold and
46.1131 + * proceed to Step 6. If a bundle has been found that is not a base
46.1132 + * bundle, proceed to Step 7.</li>
46.1133 + *
46.1134 + * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
46.1135 + * Locale) control.getFallbackLocale} method is called to get a fallback
46.1136 + * locale (alternative to the current target locale) to try further
46.1137 + * finding a resource bundle. If the method returns a non-null locale,
46.1138 + * it becomes the next target locale and the loading process starts over
46.1139 + * from Step 3. Otherwise, if a base bundle was found and put on hold in
46.1140 + * a previous Step 5, it is returned to the caller now. Otherwise, a
46.1141 + * MissingResourceException is thrown.</li>
46.1142 + *
46.1143 + * <li>At this point, we have found a resource bundle that's not the
46.1144 + * base bundle. If this bundle set its parent during its instantiation,
46.1145 + * it is returned to the caller. Otherwise, its <a
46.1146 + * href="./ResourceBundle.html#parent_chain">parent chain</a> is
46.1147 + * instantiated based on the list of candidate locales from which it was
46.1148 + * found. Finally, the bundle is returned to the caller.</li>
46.1149 + * </ol>
46.1150 + *
46.1151 + * <p>During the resource bundle loading process above, this factory
46.1152 + * method looks up the cache before calling the {@link
46.1153 + * Control#newBundle(String, Locale, String, ClassLoader, boolean)
46.1154 + * control.newBundle} method. If the time-to-live period of the
46.1155 + * resource bundle found in the cache has expired, the factory method
46.1156 + * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
46.1157 + * String, ClassLoader, ResourceBundle, long) control.needsReload}
46.1158 + * method to determine whether the resource bundle needs to be reloaded.
46.1159 + * If reloading is required, the factory method calls
46.1160 + * <code>control.newBundle</code> to reload the resource bundle. If
46.1161 + * <code>control.newBundle</code> returns <code>null</code>, the factory
46.1162 + * method puts a dummy resource bundle in the cache as a mark of
46.1163 + * nonexistent resource bundles in order to avoid lookup overhead for
46.1164 + * subsequent requests. Such dummy resource bundles are under the same
46.1165 + * expiration control as specified by <code>control</code>.
46.1166 + *
46.1167 + * <p>All resource bundles loaded are cached by default. Refer to
46.1168 + * {@link Control#getTimeToLive(String,Locale)
46.1169 + * control.getTimeToLive} for details.
46.1170 + *
46.1171 + * <p>The following is an example of the bundle loading process with the
46.1172 + * default <code>ResourceBundle.Control</code> implementation.
46.1173 + *
46.1174 + * <p>Conditions:
46.1175 + * <ul>
46.1176 + * <li>Base bundle name: <code>foo.bar.Messages</code>
46.1177 + * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
46.1178 + * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
46.1179 + * <li>Available resource bundles:
46.1180 + * <code>foo/bar/Messages_fr.properties</code> and
46.1181 + * <code>foo/bar/Messages.properties</code></li>
46.1182 + * </ul>
46.1183 + *
46.1184 + * <p>First, <code>getBundle</code> tries loading a resource bundle in
46.1185 + * the following sequence.
46.1186 + *
46.1187 + * <ul>
46.1188 + * <li>class <code>foo.bar.Messages_it_IT</code>
46.1189 + * <li>file <code>foo/bar/Messages_it_IT.properties</code>
46.1190 + * <li>class <code>foo.bar.Messages_it</code></li>
46.1191 + * <li>file <code>foo/bar/Messages_it.properties</code></li>
46.1192 + * <li>class <code>foo.bar.Messages</code></li>
46.1193 + * <li>file <code>foo/bar/Messages.properties</code></li>
46.1194 + * </ul>
46.1195 + *
46.1196 + * <p>At this point, <code>getBundle</code> finds
46.1197 + * <code>foo/bar/Messages.properties</code>, which is put on hold
46.1198 + * because it's the base bundle. <code>getBundle</code> calls {@link
46.1199 + * Control#getFallbackLocale(String, Locale)
46.1200 + * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
46.1201 + * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
46.1202 + * tries loading a bundle in the following sequence.
46.1203 + *
46.1204 + * <ul>
46.1205 + * <li>class <code>foo.bar.Messages_fr</code></li>
46.1206 + * <li>file <code>foo/bar/Messages_fr.properties</code></li>
46.1207 + * <li>class <code>foo.bar.Messages</code></li>
46.1208 + * <li>file <code>foo/bar/Messages.properties</code></li>
46.1209 + * </ul>
46.1210 + *
46.1211 + * <p><code>getBundle</code> finds
46.1212 + * <code>foo/bar/Messages_fr.properties</code> and creates a
46.1213 + * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
46.1214 + * sets up its parent chain from the list of the candiate locales. Only
46.1215 + * <code>foo/bar/Messages.properties</code> is found in the list and
46.1216 + * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
46.1217 + * that becomes the parent of the instance for
46.1218 + * <code>foo/bar/Messages_fr.properties</code>.
46.1219 + *
46.1220 + * @param baseName
46.1221 + * the base name of the resource bundle, a fully qualified
46.1222 + * class name
46.1223 + * @param targetLocale
46.1224 + * the locale for which a resource bundle is desired
46.1225 + * @param loader
46.1226 + * the class loader from which to load the resource bundle
46.1227 + * @param control
46.1228 + * the control which gives information for the resource
46.1229 + * bundle loading process
46.1230 + * @return a resource bundle for the given base name and locale
46.1231 + * @exception NullPointerException
46.1232 + * if <code>baseName</code>, <code>targetLocale</code>,
46.1233 + * <code>loader</code>, or <code>control</code> is
46.1234 + * <code>null</code>
46.1235 + * @exception MissingResourceException
46.1236 + * if no resource bundle for the specified base name can be found
46.1237 + * @exception IllegalArgumentException
46.1238 + * if the given <code>control</code> doesn't perform properly
46.1239 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
46.1240 + * Note that validation of <code>control</code> is performed as
46.1241 + * needed.
46.1242 + * @since 1.6
46.1243 + */
46.1244 + public static ResourceBundle getBundle(String baseName, Locale targetLocale,
46.1245 + ClassLoader loader, Control control) {
46.1246 + if (loader == null || control == null) {
46.1247 + throw new NullPointerException();
46.1248 + }
46.1249 + return getBundleImpl(baseName, targetLocale, loader, control);
46.1250 + }
46.1251 +
46.1252 + private static ResourceBundle getBundleImpl(String baseName, Locale locale,
46.1253 + ClassLoader loader, Control control) {
46.1254 + if (locale == null || control == null) {
46.1255 + throw new NullPointerException();
46.1256 + }
46.1257 +
46.1258 + // We create a CacheKey here for use by this call. The base
46.1259 + // name and loader will never change during the bundle loading
46.1260 + // process. We have to make sure that the locale is set before
46.1261 + // using it as a cache key.
46.1262 + CacheKey cacheKey = new CacheKey(baseName, locale, loader);
46.1263 + ResourceBundle bundle = null;
46.1264 +
46.1265 + // Quick lookup of the cache.
46.1266 + BundleReference bundleRef = cacheList.get(cacheKey);
46.1267 + if (bundleRef != null) {
46.1268 + bundle = bundleRef.get();
46.1269 + bundleRef = null;
46.1270 + }
46.1271 +
46.1272 + // If this bundle and all of its parents are valid (not expired),
46.1273 + // then return this bundle. If any of the bundles is expired, we
46.1274 + // don't call control.needsReload here but instead drop into the
46.1275 + // complete loading process below.
46.1276 + if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
46.1277 + return bundle;
46.1278 + }
46.1279 +
46.1280 + // No valid bundle was found in the cache, so we need to load the
46.1281 + // resource bundle and its parents.
46.1282 +
46.1283 + boolean isKnownControl = (control == Control.INSTANCE) ||
46.1284 + (control instanceof SingleFormatControl);
46.1285 + List<String> formats = control.getFormats(baseName);
46.1286 + if (!isKnownControl && !checkList(formats)) {
46.1287 + throw new IllegalArgumentException("Invalid Control: getFormats");
46.1288 + }
46.1289 +
46.1290 + ResourceBundle baseBundle = null;
46.1291 + for (Locale targetLocale = locale;
46.1292 + targetLocale != null;
46.1293 + targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
46.1294 + List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
46.1295 + if (!isKnownControl && !checkList(candidateLocales)) {
46.1296 + throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
46.1297 + }
46.1298 +
46.1299 + bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
46.1300 +
46.1301 + // If the loaded bundle is the base bundle and exactly for the
46.1302 + // requested locale or the only candidate locale, then take the
46.1303 + // bundle as the resulting one. If the loaded bundle is the base
46.1304 + // bundle, it's put on hold until we finish processing all
46.1305 + // fallback locales.
46.1306 + if (isValidBundle(bundle)) {
46.1307 + boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
46.1308 + if (!isBaseBundle || bundle.locale.equals(locale)
46.1309 + || (candidateLocales.size() == 1
46.1310 + && bundle.locale.equals(candidateLocales.get(0)))) {
46.1311 + break;
46.1312 + }
46.1313 +
46.1314 + // If the base bundle has been loaded, keep the reference in
46.1315 + // baseBundle so that we can avoid any redundant loading in case
46.1316 + // the control specify not to cache bundles.
46.1317 + if (isBaseBundle && baseBundle == null) {
46.1318 + baseBundle = bundle;
46.1319 + }
46.1320 + }
46.1321 + }
46.1322 +
46.1323 + if (bundle == null) {
46.1324 + if (baseBundle == null) {
46.1325 + throwMissingResourceException(baseName, locale, cacheKey.getCause());
46.1326 + }
46.1327 + bundle = baseBundle;
46.1328 + }
46.1329 +
46.1330 + return bundle;
46.1331 + }
46.1332 +
46.1333 + /**
46.1334 + * Checks if the given <code>List</code> is not null, not empty,
46.1335 + * not having null in its elements.
46.1336 + */
46.1337 + private static final boolean checkList(List a) {
46.1338 + boolean valid = (a != null && a.size() != 0);
46.1339 + if (valid) {
46.1340 + int size = a.size();
46.1341 + for (int i = 0; valid && i < size; i++) {
46.1342 + valid = (a.get(i) != null);
46.1343 + }
46.1344 + }
46.1345 + return valid;
46.1346 + }
46.1347 +
46.1348 + private static final ResourceBundle findBundle(CacheKey cacheKey,
46.1349 + List<Locale> candidateLocales,
46.1350 + List<String> formats,
46.1351 + int index,
46.1352 + Control control,
46.1353 + ResourceBundle baseBundle) {
46.1354 + Locale targetLocale = candidateLocales.get(index);
46.1355 + ResourceBundle parent = null;
46.1356 + if (index != candidateLocales.size() - 1) {
46.1357 + parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
46.1358 + control, baseBundle);
46.1359 + } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
46.1360 + return baseBundle;
46.1361 + }
46.1362 +
46.1363 + // Before we do the real loading work, see whether we need to
46.1364 + // do some housekeeping: If references to class loaders or
46.1365 + // resource bundles have been nulled out, remove all related
46.1366 + // information from the cache.
46.1367 + Object ref;
46.1368 + while ((ref = referenceQueue.poll()) != null) {
46.1369 + cacheList.remove(((CacheKeyReference)ref).getCacheKey());
46.1370 + }
46.1371 +
46.1372 + // flag indicating the resource bundle has expired in the cache
46.1373 + boolean expiredBundle = false;
46.1374 +
46.1375 + // First, look up the cache to see if it's in the cache, without
46.1376 + // attempting to load bundle.
46.1377 + cacheKey.setLocale(targetLocale);
46.1378 + ResourceBundle bundle = findBundleInCache(cacheKey, control);
46.1379 + if (isValidBundle(bundle)) {
46.1380 + expiredBundle = bundle.expired;
46.1381 + if (!expiredBundle) {
46.1382 + // If its parent is the one asked for by the candidate
46.1383 + // locales (the runtime lookup path), we can take the cached
46.1384 + // one. (If it's not identical, then we'd have to check the
46.1385 + // parent's parents to be consistent with what's been
46.1386 + // requested.)
46.1387 + if (bundle.parent == parent) {
46.1388 + return bundle;
46.1389 + }
46.1390 + // Otherwise, remove the cached one since we can't keep
46.1391 + // the same bundles having different parents.
46.1392 + BundleReference bundleRef = cacheList.get(cacheKey);
46.1393 + if (bundleRef != null && bundleRef.get() == bundle) {
46.1394 + cacheList.remove(cacheKey, bundleRef);
46.1395 + }
46.1396 + }
46.1397 + }
46.1398 +
46.1399 + if (bundle != NONEXISTENT_BUNDLE) {
46.1400 + CacheKey constKey = (CacheKey) cacheKey.clone();
46.1401 +
46.1402 + try {
46.1403 + bundle = loadBundle(cacheKey, formats, control, expiredBundle);
46.1404 + if (bundle != null) {
46.1405 + if (bundle.parent == null) {
46.1406 + bundle.setParent(parent);
46.1407 + }
46.1408 + bundle.locale = targetLocale;
46.1409 + bundle = putBundleInCache(cacheKey, bundle, control);
46.1410 + return bundle;
46.1411 + }
46.1412 +
46.1413 + // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
46.1414 + // instance for the locale.
46.1415 + putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
46.1416 + } finally {
46.1417 + if (constKey.getCause() instanceof InterruptedException) {
46.1418 + Thread.currentThread().interrupt();
46.1419 + }
46.1420 + }
46.1421 + }
46.1422 + return parent;
46.1423 + }
46.1424 +
46.1425 + private static final ResourceBundle loadBundle(CacheKey cacheKey,
46.1426 + List<String> formats,
46.1427 + Control control,
46.1428 + boolean reload) {
46.1429 +
46.1430 + // Here we actually load the bundle in the order of formats
46.1431 + // specified by the getFormats() value.
46.1432 + Locale targetLocale = cacheKey.getLocale();
46.1433 +
46.1434 + ResourceBundle bundle = null;
46.1435 + int size = formats.size();
46.1436 + for (int i = 0; i < size; i++) {
46.1437 + String format = formats.get(i);
46.1438 + try {
46.1439 + bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
46.1440 + cacheKey.getLoader(), reload);
46.1441 + } catch (LinkageError error) {
46.1442 + // We need to handle the LinkageError case due to
46.1443 + // inconsistent case-sensitivity in ClassLoader.
46.1444 + // See 6572242 for details.
46.1445 + cacheKey.setCause(error);
46.1446 + } catch (Exception cause) {
46.1447 + cacheKey.setCause(cause);
46.1448 + }
46.1449 + if (bundle != null) {
46.1450 + // Set the format in the cache key so that it can be
46.1451 + // used when calling needsReload later.
46.1452 + cacheKey.setFormat(format);
46.1453 + bundle.name = cacheKey.getName();
46.1454 + bundle.locale = targetLocale;
46.1455 + // Bundle provider might reuse instances. So we should make
46.1456 + // sure to clear the expired flag here.
46.1457 + bundle.expired = false;
46.1458 + break;
46.1459 + }
46.1460 + }
46.1461 +
46.1462 + return bundle;
46.1463 + }
46.1464 +
46.1465 + private static final boolean isValidBundle(ResourceBundle bundle) {
46.1466 + return bundle != null && bundle != NONEXISTENT_BUNDLE;
46.1467 + }
46.1468 +
46.1469 + /**
46.1470 + * Determines whether any of resource bundles in the parent chain,
46.1471 + * including the leaf, have expired.
46.1472 + */
46.1473 + private static final boolean hasValidParentChain(ResourceBundle bundle) {
46.1474 + long now = System.currentTimeMillis();
46.1475 + while (bundle != null) {
46.1476 + if (bundle.expired) {
46.1477 + return false;
46.1478 + }
46.1479 + CacheKey key = bundle.cacheKey;
46.1480 + if (key != null) {
46.1481 + long expirationTime = key.expirationTime;
46.1482 + if (expirationTime >= 0 && expirationTime <= now) {
46.1483 + return false;
46.1484 + }
46.1485 + }
46.1486 + bundle = bundle.parent;
46.1487 + }
46.1488 + return true;
46.1489 + }
46.1490 +
46.1491 + /**
46.1492 + * Throw a MissingResourceException with proper message
46.1493 + */
46.1494 + private static final void throwMissingResourceException(String baseName,
46.1495 + Locale locale,
46.1496 + Throwable cause) {
46.1497 + // If the cause is a MissingResourceException, avoid creating
46.1498 + // a long chain. (6355009)
46.1499 + if (cause instanceof MissingResourceException) {
46.1500 + cause = null;
46.1501 + }
46.1502 + throw new MissingResourceException("Can't find bundle for base name "
46.1503 + + baseName + ", locale " + locale,
46.1504 + baseName + "_" + locale, // className
46.1505 + "", // key
46.1506 + cause);
46.1507 + }
46.1508 +
46.1509 + /**
46.1510 + * Finds a bundle in the cache. Any expired bundles are marked as
46.1511 + * `expired' and removed from the cache upon return.
46.1512 + *
46.1513 + * @param cacheKey the key to look up the cache
46.1514 + * @param control the Control to be used for the expiration control
46.1515 + * @return the cached bundle, or null if the bundle is not found in the
46.1516 + * cache or its parent has expired. <code>bundle.expire</code> is true
46.1517 + * upon return if the bundle in the cache has expired.
46.1518 + */
46.1519 + private static final ResourceBundle findBundleInCache(CacheKey cacheKey,
46.1520 + Control control) {
46.1521 + BundleReference bundleRef = cacheList.get(cacheKey);
46.1522 + if (bundleRef == null) {
46.1523 + return null;
46.1524 + }
46.1525 + ResourceBundle bundle = bundleRef.get();
46.1526 + if (bundle == null) {
46.1527 + return null;
46.1528 + }
46.1529 + ResourceBundle p = bundle.parent;
46.1530 + assert p != NONEXISTENT_BUNDLE;
46.1531 + // If the parent has expired, then this one must also expire. We
46.1532 + // check only the immediate parent because the actual loading is
46.1533 + // done from the root (base) to leaf (child) and the purpose of
46.1534 + // checking is to propagate expiration towards the leaf. For
46.1535 + // example, if the requested locale is ja_JP_JP and there are
46.1536 + // bundles for all of the candidates in the cache, we have a list,
46.1537 + //
46.1538 + // base <- ja <- ja_JP <- ja_JP_JP
46.1539 + //
46.1540 + // If ja has expired, then it will reload ja and the list becomes a
46.1541 + // tree.
46.1542 + //
46.1543 + // base <- ja (new)
46.1544 + // " <- ja (expired) <- ja_JP <- ja_JP_JP
46.1545 + //
46.1546 + // When looking up ja_JP in the cache, it finds ja_JP in the cache
46.1547 + // which references to the expired ja. Then, ja_JP is marked as
46.1548 + // expired and removed from the cache. This will be propagated to
46.1549 + // ja_JP_JP.
46.1550 + //
46.1551 + // Now, it's possible, for example, that while loading new ja_JP,
46.1552 + // someone else has started loading the same bundle and finds the
46.1553 + // base bundle has expired. Then, what we get from the first
46.1554 + // getBundle call includes the expired base bundle. However, if
46.1555 + // someone else didn't start its loading, we wouldn't know if the
46.1556 + // base bundle has expired at the end of the loading process. The
46.1557 + // expiration control doesn't guarantee that the returned bundle and
46.1558 + // its parents haven't expired.
46.1559 + //
46.1560 + // We could check the entire parent chain to see if there's any in
46.1561 + // the chain that has expired. But this process may never end. An
46.1562 + // extreme case would be that getTimeToLive returns 0 and
46.1563 + // needsReload always returns true.
46.1564 + if (p != null && p.expired) {
46.1565 + assert bundle != NONEXISTENT_BUNDLE;
46.1566 + bundle.expired = true;
46.1567 + bundle.cacheKey = null;
46.1568 + cacheList.remove(cacheKey, bundleRef);
46.1569 + bundle = null;
46.1570 + } else {
46.1571 + CacheKey key = bundleRef.getCacheKey();
46.1572 + long expirationTime = key.expirationTime;
46.1573 + if (!bundle.expired && expirationTime >= 0 &&
46.1574 + expirationTime <= System.currentTimeMillis()) {
46.1575 + // its TTL period has expired.
46.1576 + if (bundle != NONEXISTENT_BUNDLE) {
46.1577 + // Synchronize here to call needsReload to avoid
46.1578 + // redundant concurrent calls for the same bundle.
46.1579 + synchronized (bundle) {
46.1580 + expirationTime = key.expirationTime;
46.1581 + if (!bundle.expired && expirationTime >= 0 &&
46.1582 + expirationTime <= System.currentTimeMillis()) {
46.1583 + try {
46.1584 + bundle.expired = control.needsReload(key.getName(),
46.1585 + key.getLocale(),
46.1586 + key.getFormat(),
46.1587 + key.getLoader(),
46.1588 + bundle,
46.1589 + key.loadTime);
46.1590 + } catch (Exception e) {
46.1591 + cacheKey.setCause(e);
46.1592 + }
46.1593 + if (bundle.expired) {
46.1594 + // If the bundle needs to be reloaded, then
46.1595 + // remove the bundle from the cache, but
46.1596 + // return the bundle with the expired flag
46.1597 + // on.
46.1598 + bundle.cacheKey = null;
46.1599 + cacheList.remove(cacheKey, bundleRef);
46.1600 + } else {
46.1601 + // Update the expiration control info. and reuse
46.1602 + // the same bundle instance
46.1603 + setExpirationTime(key, control);
46.1604 + }
46.1605 + }
46.1606 + }
46.1607 + } else {
46.1608 + // We just remove NONEXISTENT_BUNDLE from the cache.
46.1609 + cacheList.remove(cacheKey, bundleRef);
46.1610 + bundle = null;
46.1611 + }
46.1612 + }
46.1613 + }
46.1614 + return bundle;
46.1615 + }
46.1616 +
46.1617 + /**
46.1618 + * Put a new bundle in the cache.
46.1619 + *
46.1620 + * @param cacheKey the key for the resource bundle
46.1621 + * @param bundle the resource bundle to be put in the cache
46.1622 + * @return the ResourceBundle for the cacheKey; if someone has put
46.1623 + * the bundle before this call, the one found in the cache is
46.1624 + * returned.
46.1625 + */
46.1626 + private static final ResourceBundle putBundleInCache(CacheKey cacheKey,
46.1627 + ResourceBundle bundle,
46.1628 + Control control) {
46.1629 + setExpirationTime(cacheKey, control);
46.1630 + if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
46.1631 + CacheKey key = (CacheKey) cacheKey.clone();
46.1632 + BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
46.1633 + bundle.cacheKey = key;
46.1634 +
46.1635 + // Put the bundle in the cache if it's not been in the cache.
46.1636 + BundleReference result = cacheList.putIfAbsent(key, bundleRef);
46.1637 +
46.1638 + // If someone else has put the same bundle in the cache before
46.1639 + // us and it has not expired, we should use the one in the cache.
46.1640 + if (result != null) {
46.1641 + ResourceBundle rb = result.get();
46.1642 + if (rb != null && !rb.expired) {
46.1643 + // Clear the back link to the cache key
46.1644 + bundle.cacheKey = null;
46.1645 + bundle = rb;
46.1646 + // Clear the reference in the BundleReference so that
46.1647 + // it won't be enqueued.
46.1648 + bundleRef.clear();
46.1649 + } else {
46.1650 + // Replace the invalid (garbage collected or expired)
46.1651 + // instance with the valid one.
46.1652 + cacheList.put(key, bundleRef);
46.1653 + }
46.1654 + }
46.1655 + }
46.1656 + return bundle;
46.1657 + }
46.1658 +
46.1659 + private static final void setExpirationTime(CacheKey cacheKey, Control control) {
46.1660 + long ttl = control.getTimeToLive(cacheKey.getName(),
46.1661 + cacheKey.getLocale());
46.1662 + if (ttl >= 0) {
46.1663 + // If any expiration time is specified, set the time to be
46.1664 + // expired in the cache.
46.1665 + long now = System.currentTimeMillis();
46.1666 + cacheKey.loadTime = now;
46.1667 + cacheKey.expirationTime = now + ttl;
46.1668 + } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
46.1669 + cacheKey.expirationTime = ttl;
46.1670 + } else {
46.1671 + throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
46.1672 + }
46.1673 + }
46.1674 +
46.1675 + /**
46.1676 + * Removes all resource bundles from the cache that have been loaded
46.1677 + * using the caller's class loader.
46.1678 + *
46.1679 + * @since 1.6
46.1680 + * @see ResourceBundle.Control#getTimeToLive(String,Locale)
46.1681 + */
46.1682 + public static final void clearCache() {
46.1683 + clearCache(getLoader());
46.1684 + }
46.1685 +
46.1686 + /**
46.1687 + * Removes all resource bundles from the cache that have been loaded
46.1688 + * using the given class loader.
46.1689 + *
46.1690 + * @param loader the class loader
46.1691 + * @exception NullPointerException if <code>loader</code> is null
46.1692 + * @since 1.6
46.1693 + * @see ResourceBundle.Control#getTimeToLive(String,Locale)
46.1694 + */
46.1695 + public static final void clearCache(ClassLoader loader) {
46.1696 + if (loader == null) {
46.1697 + throw new NullPointerException();
46.1698 + }
46.1699 + Set<CacheKey> set = cacheList.keySet();
46.1700 + for (CacheKey key : set) {
46.1701 + if (key.getLoader() == loader) {
46.1702 + set.remove(key);
46.1703 + }
46.1704 + }
46.1705 + }
46.1706 +
46.1707 + /**
46.1708 + * Gets an object for the given key from this resource bundle.
46.1709 + * Returns null if this resource bundle does not contain an
46.1710 + * object for the given key.
46.1711 + *
46.1712 + * @param key the key for the desired object
46.1713 + * @exception NullPointerException if <code>key</code> is <code>null</code>
46.1714 + * @return the object for the given key, or null
46.1715 + */
46.1716 + protected abstract Object handleGetObject(String key);
46.1717 +
46.1718 + /**
46.1719 + * Returns an enumeration of the keys.
46.1720 + *
46.1721 + * @return an <code>Enumeration</code> of the keys contained in
46.1722 + * this <code>ResourceBundle</code> and its parent bundles.
46.1723 + */
46.1724 + public abstract Enumeration<String> getKeys();
46.1725 +
46.1726 + /**
46.1727 + * Determines whether the given <code>key</code> is contained in
46.1728 + * this <code>ResourceBundle</code> or its parent bundles.
46.1729 + *
46.1730 + * @param key
46.1731 + * the resource <code>key</code>
46.1732 + * @return <code>true</code> if the given <code>key</code> is
46.1733 + * contained in this <code>ResourceBundle</code> or its
46.1734 + * parent bundles; <code>false</code> otherwise.
46.1735 + * @exception NullPointerException
46.1736 + * if <code>key</code> is <code>null</code>
46.1737 + * @since 1.6
46.1738 + */
46.1739 + public boolean containsKey(String key) {
46.1740 + if (key == null) {
46.1741 + throw new NullPointerException();
46.1742 + }
46.1743 + for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
46.1744 + if (rb.handleKeySet().contains(key)) {
46.1745 + return true;
46.1746 + }
46.1747 + }
46.1748 + return false;
46.1749 + }
46.1750 +
46.1751 + /**
46.1752 + * Returns a <code>Set</code> of all keys contained in this
46.1753 + * <code>ResourceBundle</code> and its parent bundles.
46.1754 + *
46.1755 + * @return a <code>Set</code> of all keys contained in this
46.1756 + * <code>ResourceBundle</code> and its parent bundles.
46.1757 + * @since 1.6
46.1758 + */
46.1759 + public Set<String> keySet() {
46.1760 + Set<String> keys = new HashSet<>();
46.1761 + for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
46.1762 + keys.addAll(rb.handleKeySet());
46.1763 + }
46.1764 + return keys;
46.1765 + }
46.1766 +
46.1767 + /**
46.1768 + * Returns a <code>Set</code> of the keys contained <em>only</em>
46.1769 + * in this <code>ResourceBundle</code>.
46.1770 + *
46.1771 + * <p>The default implementation returns a <code>Set</code> of the
46.1772 + * keys returned by the {@link #getKeys() getKeys} method except
46.1773 + * for the ones for which the {@link #handleGetObject(String)
46.1774 + * handleGetObject} method returns <code>null</code>. Once the
46.1775 + * <code>Set</code> has been created, the value is kept in this
46.1776 + * <code>ResourceBundle</code> in order to avoid producing the
46.1777 + * same <code>Set</code> in subsequent calls. Subclasses can
46.1778 + * override this method for faster handling.
46.1779 + *
46.1780 + * @return a <code>Set</code> of the keys contained only in this
46.1781 + * <code>ResourceBundle</code>
46.1782 + * @since 1.6
46.1783 + */
46.1784 + protected Set<String> handleKeySet() {
46.1785 + if (keySet == null) {
46.1786 + synchronized (this) {
46.1787 + if (keySet == null) {
46.1788 + Set<String> keys = new HashSet<>();
46.1789 + Enumeration<String> enumKeys = getKeys();
46.1790 + while (enumKeys.hasMoreElements()) {
46.1791 + String key = enumKeys.nextElement();
46.1792 + if (handleGetObject(key) != null) {
46.1793 + keys.add(key);
46.1794 + }
46.1795 + }
46.1796 + keySet = keys;
46.1797 + }
46.1798 + }
46.1799 + }
46.1800 + return keySet;
46.1801 + }
46.1802 +
46.1803 +
46.1804 +
46.1805 + /**
46.1806 + * <code>ResourceBundle.Control</code> defines a set of callback methods
46.1807 + * that are invoked by the {@link ResourceBundle#getBundle(String,
46.1808 + * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
46.1809 + * methods during the bundle loading process. In other words, a
46.1810 + * <code>ResourceBundle.Control</code> collaborates with the factory
46.1811 + * methods for loading resource bundles. The default implementation of
46.1812 + * the callback methods provides the information necessary for the
46.1813 + * factory methods to perform the <a
46.1814 + * href="./ResourceBundle.html#default_behavior">default behavior</a>.
46.1815 + *
46.1816 + * <p>In addition to the callback methods, the {@link
46.1817 + * #toBundleName(String, Locale) toBundleName} and {@link
46.1818 + * #toResourceName(String, String) toResourceName} methods are defined
46.1819 + * primarily for convenience in implementing the callback
46.1820 + * methods. However, the <code>toBundleName</code> method could be
46.1821 + * overridden to provide different conventions in the organization and
46.1822 + * packaging of localized resources. The <code>toResourceName</code>
46.1823 + * method is <code>final</code> to avoid use of wrong resource and class
46.1824 + * name separators.
46.1825 + *
46.1826 + * <p>Two factory methods, {@link #getControl(List)} and {@link
46.1827 + * #getNoFallbackControl(List)}, provide
46.1828 + * <code>ResourceBundle.Control</code> instances that implement common
46.1829 + * variations of the default bundle loading process.
46.1830 + *
46.1831 + * <p>The formats returned by the {@link Control#getFormats(String)
46.1832 + * getFormats} method and candidate locales returned by the {@link
46.1833 + * ResourceBundle.Control#getCandidateLocales(String, Locale)
46.1834 + * getCandidateLocales} method must be consistent in all
46.1835 + * <code>ResourceBundle.getBundle</code> invocations for the same base
46.1836 + * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
46.1837 + * may return unintended bundles. For example, if only
46.1838 + * <code>"java.class"</code> is returned by the <code>getFormats</code>
46.1839 + * method for the first call to <code>ResourceBundle.getBundle</code>
46.1840 + * and only <code>"java.properties"</code> for the second call, then the
46.1841 + * second call will return the class-based one that has been cached
46.1842 + * during the first call.
46.1843 + *
46.1844 + * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
46.1845 + * if it's simultaneously used by multiple threads.
46.1846 + * <code>ResourceBundle.getBundle</code> does not synchronize to call
46.1847 + * the <code>ResourceBundle.Control</code> methods. The default
46.1848 + * implementations of the methods are thread-safe.
46.1849 + *
46.1850 + * <p>Applications can specify <code>ResourceBundle.Control</code>
46.1851 + * instances returned by the <code>getControl</code> factory methods or
46.1852 + * created from a subclass of <code>ResourceBundle.Control</code> to
46.1853 + * customize the bundle loading process. The following are examples of
46.1854 + * changing the default bundle loading process.
46.1855 + *
46.1856 + * <p><b>Example 1</b>
46.1857 + *
46.1858 + * <p>The following code lets <code>ResourceBundle.getBundle</code> look
46.1859 + * up only properties-based resources.
46.1860 + *
46.1861 + * <pre>
46.1862 + * import java.util.*;
46.1863 + * import static java.util.ResourceBundle.Control.*;
46.1864 + * ...
46.1865 + * ResourceBundle bundle =
46.1866 + * ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
46.1867 + * ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
46.1868 + * </pre>
46.1869 + *
46.1870 + * Given the resource bundles in the <a
46.1871 + * href="./ResourceBundle.html#default_behavior_example">example</a> in
46.1872 + * the <code>ResourceBundle.getBundle</code> description, this
46.1873 + * <code>ResourceBundle.getBundle</code> call loads
46.1874 + * <code>MyResources_fr_CH.properties</code> whose parent is
46.1875 + * <code>MyResources_fr.properties</code> whose parent is
46.1876 + * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
46.1877 + * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
46.1878 + *
46.1879 + * <p><b>Example 2</b>
46.1880 + *
46.1881 + * <p>The following is an example of loading XML-based bundles
46.1882 + * using {@link Properties#loadFromXML(java.io.InputStream)
46.1883 + * Properties.loadFromXML}.
46.1884 + *
46.1885 + * <pre>
46.1886 + * ResourceBundle rb = ResourceBundle.getBundle("Messages",
46.1887 + * new ResourceBundle.Control() {
46.1888 + * public List<String> getFormats(String baseName) {
46.1889 + * if (baseName == null)
46.1890 + * throw new NullPointerException();
46.1891 + * return Arrays.asList("xml");
46.1892 + * }
46.1893 + * public ResourceBundle newBundle(String baseName,
46.1894 + * Locale locale,
46.1895 + * String format,
46.1896 + * ClassLoader loader,
46.1897 + * boolean reload)
46.1898 + * throws IllegalAccessException,
46.1899 + * InstantiationException,
46.1900 + * IOException {
46.1901 + * if (baseName == null || locale == null
46.1902 + * || format == null || loader == null)
46.1903 + * throw new NullPointerException();
46.1904 + * ResourceBundle bundle = null;
46.1905 + * if (format.equals("xml")) {
46.1906 + * String bundleName = toBundleName(baseName, locale);
46.1907 + * String resourceName = toResourceName(bundleName, format);
46.1908 + * InputStream stream = null;
46.1909 + * if (reload) {
46.1910 + * URL url = loader.getResource(resourceName);
46.1911 + * if (url != null) {
46.1912 + * URLConnection connection = url.openConnection();
46.1913 + * if (connection != null) {
46.1914 + * // Disable caches to get fresh data for
46.1915 + * // reloading.
46.1916 + * connection.setUseCaches(false);
46.1917 + * stream = connection.getInputStream();
46.1918 + * }
46.1919 + * }
46.1920 + * } else {
46.1921 + * stream = loader.getResourceAsStream(resourceName);
46.1922 + * }
46.1923 + * if (stream != null) {
46.1924 + * BufferedInputStream bis = new BufferedInputStream(stream);
46.1925 + * bundle = new XMLResourceBundle(bis);
46.1926 + * bis.close();
46.1927 + * }
46.1928 + * }
46.1929 + * return bundle;
46.1930 + * }
46.1931 + * });
46.1932 + *
46.1933 + * ...
46.1934 + *
46.1935 + * private static class XMLResourceBundle extends ResourceBundle {
46.1936 + * private Properties props;
46.1937 + * XMLResourceBundle(InputStream stream) throws IOException {
46.1938 + * props = new Properties();
46.1939 + * props.loadFromXML(stream);
46.1940 + * }
46.1941 + * protected Object handleGetObject(String key) {
46.1942 + * return props.getProperty(key);
46.1943 + * }
46.1944 + * public Enumeration<String> getKeys() {
46.1945 + * ...
46.1946 + * }
46.1947 + * }
46.1948 + * </pre>
46.1949 + *
46.1950 + * @since 1.6
46.1951 + */
46.1952 + public static class Control {
46.1953 + /**
46.1954 + * The default format <code>List</code>, which contains the strings
46.1955 + * <code>"java.class"</code> and <code>"java.properties"</code>, in
46.1956 + * this order. This <code>List</code> is {@linkplain
46.1957 + * Collections#unmodifiableList(List) unmodifiable}.
46.1958 + *
46.1959 + * @see #getFormats(String)
46.1960 + */
46.1961 + public static final List<String> FORMAT_DEFAULT
46.1962 + = Collections.unmodifiableList(Arrays.asList("java.class",
46.1963 + "java.properties"));
46.1964 +
46.1965 + /**
46.1966 + * The class-only format <code>List</code> containing
46.1967 + * <code>"java.class"</code>. This <code>List</code> is {@linkplain
46.1968 + * Collections#unmodifiableList(List) unmodifiable}.
46.1969 + *
46.1970 + * @see #getFormats(String)
46.1971 + */
46.1972 + public static final List<String> FORMAT_CLASS
46.1973 + = Collections.unmodifiableList(Arrays.asList("java.class"));
46.1974 +
46.1975 + /**
46.1976 + * The properties-only format <code>List</code> containing
46.1977 + * <code>"java.properties"</code>. This <code>List</code> is
46.1978 + * {@linkplain Collections#unmodifiableList(List) unmodifiable}.
46.1979 + *
46.1980 + * @see #getFormats(String)
46.1981 + */
46.1982 + public static final List<String> FORMAT_PROPERTIES
46.1983 + = Collections.unmodifiableList(Arrays.asList("java.properties"));
46.1984 +
46.1985 + /**
46.1986 + * The time-to-live constant for not caching loaded resource bundle
46.1987 + * instances.
46.1988 + *
46.1989 + * @see #getTimeToLive(String, Locale)
46.1990 + */
46.1991 + public static final long TTL_DONT_CACHE = -1;
46.1992 +
46.1993 + /**
46.1994 + * The time-to-live constant for disabling the expiration control
46.1995 + * for loaded resource bundle instances in the cache.
46.1996 + *
46.1997 + * @see #getTimeToLive(String, Locale)
46.1998 + */
46.1999 + public static final long TTL_NO_EXPIRATION_CONTROL = -2;
46.2000 +
46.2001 + private static final Control INSTANCE = new Control();
46.2002 +
46.2003 + /**
46.2004 + * Sole constructor. (For invocation by subclass constructors,
46.2005 + * typically implicit.)
46.2006 + */
46.2007 + protected Control() {
46.2008 + }
46.2009 +
46.2010 + /**
46.2011 + * Returns a <code>ResourceBundle.Control</code> in which the {@link
46.2012 + * #getFormats(String) getFormats} method returns the specified
46.2013 + * <code>formats</code>. The <code>formats</code> must be equal to
46.2014 + * one of {@link Control#FORMAT_PROPERTIES}, {@link
46.2015 + * Control#FORMAT_CLASS} or {@link
46.2016 + * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
46.2017 + * instances returned by this method are singletons and thread-safe.
46.2018 + *
46.2019 + * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
46.2020 + * instantiating the <code>ResourceBundle.Control</code> class,
46.2021 + * except that this method returns a singleton.
46.2022 + *
46.2023 + * @param formats
46.2024 + * the formats to be returned by the
46.2025 + * <code>ResourceBundle.Control.getFormats</code> method
46.2026 + * @return a <code>ResourceBundle.Control</code> supporting the
46.2027 + * specified <code>formats</code>
46.2028 + * @exception NullPointerException
46.2029 + * if <code>formats</code> is <code>null</code>
46.2030 + * @exception IllegalArgumentException
46.2031 + * if <code>formats</code> is unknown
46.2032 + */
46.2033 + public static final Control getControl(List<String> formats) {
46.2034 + if (formats.equals(Control.FORMAT_PROPERTIES)) {
46.2035 + return SingleFormatControl.PROPERTIES_ONLY;
46.2036 + }
46.2037 + if (formats.equals(Control.FORMAT_CLASS)) {
46.2038 + return SingleFormatControl.CLASS_ONLY;
46.2039 + }
46.2040 + if (formats.equals(Control.FORMAT_DEFAULT)) {
46.2041 + return Control.INSTANCE;
46.2042 + }
46.2043 + throw new IllegalArgumentException();
46.2044 + }
46.2045 +
46.2046 + /**
46.2047 + * Returns a <code>ResourceBundle.Control</code> in which the {@link
46.2048 + * #getFormats(String) getFormats} method returns the specified
46.2049 + * <code>formats</code> and the {@link
46.2050 + * Control#getFallbackLocale(String, Locale) getFallbackLocale}
46.2051 + * method returns <code>null</code>. The <code>formats</code> must
46.2052 + * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
46.2053 + * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
46.2054 + * <code>ResourceBundle.Control</code> instances returned by this
46.2055 + * method are singletons and thread-safe.
46.2056 + *
46.2057 + * @param formats
46.2058 + * the formats to be returned by the
46.2059 + * <code>ResourceBundle.Control.getFormats</code> method
46.2060 + * @return a <code>ResourceBundle.Control</code> supporting the
46.2061 + * specified <code>formats</code> with no fallback
46.2062 + * <code>Locale</code> support
46.2063 + * @exception NullPointerException
46.2064 + * if <code>formats</code> is <code>null</code>
46.2065 + * @exception IllegalArgumentException
46.2066 + * if <code>formats</code> is unknown
46.2067 + */
46.2068 + public static final Control getNoFallbackControl(List<String> formats) {
46.2069 + if (formats.equals(Control.FORMAT_DEFAULT)) {
46.2070 + return NoFallbackControl.NO_FALLBACK;
46.2071 + }
46.2072 + if (formats.equals(Control.FORMAT_PROPERTIES)) {
46.2073 + return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
46.2074 + }
46.2075 + if (formats.equals(Control.FORMAT_CLASS)) {
46.2076 + return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
46.2077 + }
46.2078 + throw new IllegalArgumentException();
46.2079 + }
46.2080 +
46.2081 + /**
46.2082 + * Returns a <code>List</code> of <code>String</code>s containing
46.2083 + * formats to be used to load resource bundles for the given
46.2084 + * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
46.2085 + * factory method tries to load resource bundles with formats in the
46.2086 + * order specified by the list. The list returned by this method
46.2087 + * must have at least one <code>String</code>. The predefined
46.2088 + * formats are <code>"java.class"</code> for class-based resource
46.2089 + * bundles and <code>"java.properties"</code> for {@linkplain
46.2090 + * PropertyResourceBundle properties-based} ones. Strings starting
46.2091 + * with <code>"java."</code> are reserved for future extensions and
46.2092 + * must not be used by application-defined formats.
46.2093 + *
46.2094 + * <p>It is not a requirement to return an immutable (unmodifiable)
46.2095 + * <code>List</code>. However, the returned <code>List</code> must
46.2096 + * not be mutated after it has been returned by
46.2097 + * <code>getFormats</code>.
46.2098 + *
46.2099 + * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
46.2100 + * that the <code>ResourceBundle.getBundle</code> factory method
46.2101 + * looks up first class-based resource bundles, then
46.2102 + * properties-based ones.
46.2103 + *
46.2104 + * @param baseName
46.2105 + * the base name of the resource bundle, a fully qualified class
46.2106 + * name
46.2107 + * @return a <code>List</code> of <code>String</code>s containing
46.2108 + * formats for loading resource bundles.
46.2109 + * @exception NullPointerException
46.2110 + * if <code>baseName</code> is null
46.2111 + * @see #FORMAT_DEFAULT
46.2112 + * @see #FORMAT_CLASS
46.2113 + * @see #FORMAT_PROPERTIES
46.2114 + */
46.2115 + public List<String> getFormats(String baseName) {
46.2116 + if (baseName == null) {
46.2117 + throw new NullPointerException();
46.2118 + }
46.2119 + return FORMAT_DEFAULT;
46.2120 + }
46.2121 +
46.2122 + /**
46.2123 + * Returns a <code>List</code> of <code>Locale</code>s as candidate
46.2124 + * locales for <code>baseName</code> and <code>locale</code>. This
46.2125 + * method is called by the <code>ResourceBundle.getBundle</code>
46.2126 + * factory method each time the factory method tries finding a
46.2127 + * resource bundle for a target <code>Locale</code>.
46.2128 + *
46.2129 + * <p>The sequence of the candidate locales also corresponds to the
46.2130 + * runtime resource lookup path (also known as the <I>parent
46.2131 + * chain</I>), if the corresponding resource bundles for the
46.2132 + * candidate locales exist and their parents are not defined by
46.2133 + * loaded resource bundles themselves. The last element of the list
46.2134 + * must be a {@linkplain Locale#ROOT root locale} if it is desired to
46.2135 + * have the base bundle as the terminal of the parent chain.
46.2136 + *
46.2137 + * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
46.2138 + * root locale), a <code>List</code> containing only the root
46.2139 + * <code>Locale</code> must be returned. In this case, the
46.2140 + * <code>ResourceBundle.getBundle</code> factory method loads only
46.2141 + * the base bundle as the resulting resource bundle.
46.2142 + *
46.2143 + * <p>It is not a requirement to return an immutable (unmodifiable)
46.2144 + * <code>List</code>. However, the returned <code>List</code> must not
46.2145 + * be mutated after it has been returned by
46.2146 + * <code>getCandidateLocales</code>.
46.2147 + *
46.2148 + * <p>The default implementation returns a <code>List</code> containing
46.2149 + * <code>Locale</code>s using the rules described below. In the
46.2150 + * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
46.2151 + * respectively represent non-empty language, script, country, and
46.2152 + * variant. For example, [<em>L</em>, <em>C</em>] represents a
46.2153 + * <code>Locale</code> that has non-empty values only for language and
46.2154 + * country. The form <em>L</em>("xx") represents the (non-empty)
46.2155 + * language value is "xx". For all cases, <code>Locale</code>s whose
46.2156 + * final component values are empty strings are omitted.
46.2157 + *
46.2158 + * <ol><li>For an input <code>Locale</code> with an empty script value,
46.2159 + * append candidate <code>Locale</code>s by omitting the final component
46.2160 + * one by one as below:
46.2161 + *
46.2162 + * <ul>
46.2163 + * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
46.2164 + * <li> [<em>L</em>, <em>C</em>]
46.2165 + * <li> [<em>L</em>]
46.2166 + * <li> <code>Locale.ROOT</code>
46.2167 + * </ul>
46.2168 + *
46.2169 + * <li>For an input <code>Locale</code> with a non-empty script value,
46.2170 + * append candidate <code>Locale</code>s by omitting the final component
46.2171 + * up to language, then append candidates generated from the
46.2172 + * <code>Locale</code> with country and variant restored:
46.2173 + *
46.2174 + * <ul>
46.2175 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
46.2176 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
46.2177 + * <li> [<em>L</em>, <em>S</em>]
46.2178 + * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
46.2179 + * <li> [<em>L</em>, <em>C</em>]
46.2180 + * <li> [<em>L</em>]
46.2181 + * <li> <code>Locale.ROOT</code>
46.2182 + * </ul>
46.2183 + *
46.2184 + * <li>For an input <code>Locale</code> with a variant value consisting
46.2185 + * of multiple subtags separated by underscore, generate candidate
46.2186 + * <code>Locale</code>s by omitting the variant subtags one by one, then
46.2187 + * insert them after every occurence of <code> Locale</code>s with the
46.2188 + * full variant value in the original list. For example, if the
46.2189 + * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
46.2190 + *
46.2191 + * <ul>
46.2192 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
46.2193 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
46.2194 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
46.2195 + * <li> [<em>L</em>, <em>S</em>]
46.2196 + * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
46.2197 + * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
46.2198 + * <li> [<em>L</em>, <em>C</em>]
46.2199 + * <li> [<em>L</em>]
46.2200 + * <li> <code>Locale.ROOT</code>
46.2201 + * </ul>
46.2202 + *
46.2203 + * <li>Special cases for Chinese. When an input <code>Locale</code> has the
46.2204 + * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
46.2205 + * "Hant" (Traditional) might be supplied, depending on the country.
46.2206 + * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
46.2207 + * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
46.2208 + * or "TW" (Taiwan), "Hant" is supplied. For all other countries or when the country
46.2209 + * is empty, no script is supplied. For example, for <code>Locale("zh", "CN")
46.2210 + * </code>, the candidate list will be:
46.2211 + * <ul>
46.2212 + * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
46.2213 + * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
46.2214 + * <li> [<em>L</em>("zh"), <em>C</em>("CN")]
46.2215 + * <li> [<em>L</em>("zh")]
46.2216 + * <li> <code>Locale.ROOT</code>
46.2217 + * </ul>
46.2218 + *
46.2219 + * For <code>Locale("zh", "TW")</code>, the candidate list will be:
46.2220 + * <ul>
46.2221 + * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
46.2222 + * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
46.2223 + * <li> [<em>L</em>("zh"), <em>C</em>("TW")]
46.2224 + * <li> [<em>L</em>("zh")]
46.2225 + * <li> <code>Locale.ROOT</code>
46.2226 + * </ul>
46.2227 + *
46.2228 + * <li>Special cases for Norwegian. Both <code>Locale("no", "NO",
46.2229 + * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
46.2230 + * Nynorsk. When a locale's language is "nn", the standard candidate
46.2231 + * list is generated up to [<em>L</em>("nn")], and then the following
46.2232 + * candidates are added:
46.2233 + *
46.2234 + * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
46.2235 + * <li> [<em>L</em>("no"), <em>C</em>("NO")]
46.2236 + * <li> [<em>L</em>("no")]
46.2237 + * <li> <code>Locale.ROOT</code>
46.2238 + * </ul>
46.2239 + *
46.2240 + * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
46.2241 + * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
46.2242 + * followed.
46.2243 + *
46.2244 + * <p>Also, Java treats the language "no" as a synonym of Norwegian
46.2245 + * Bokmål "nb". Except for the single case <code>Locale("no",
46.2246 + * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
46.2247 + * has language "no" or "nb", candidate <code>Locale</code>s with
46.2248 + * language code "no" and "nb" are interleaved, first using the
46.2249 + * requested language, then using its synonym. For example,
46.2250 + * <code>Locale("nb", "NO", "POSIX")</code> generates the following
46.2251 + * candidate list:
46.2252 + *
46.2253 + * <ul>
46.2254 + * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
46.2255 + * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
46.2256 + * <li> [<em>L</em>("nb"), <em>C</em>("NO")]
46.2257 + * <li> [<em>L</em>("no"), <em>C</em>("NO")]
46.2258 + * <li> [<em>L</em>("nb")]
46.2259 + * <li> [<em>L</em>("no")]
46.2260 + * <li> <code>Locale.ROOT</code>
46.2261 + * </ul>
46.2262 + *
46.2263 + * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
46.2264 + * except that locales with "no" would appear before the corresponding
46.2265 + * locales with "nb".</li>
46.2266 + *
46.2267 + * </li>
46.2268 + * </ol>
46.2269 + *
46.2270 + * <p>The default implementation uses an {@link ArrayList} that
46.2271 + * overriding implementations may modify before returning it to the
46.2272 + * caller. However, a subclass must not modify it after it has
46.2273 + * been returned by <code>getCandidateLocales</code>.
46.2274 + *
46.2275 + * <p>For example, if the given <code>baseName</code> is "Messages"
46.2276 + * and the given <code>locale</code> is
46.2277 + * <code>Locale("ja", "", "XX")</code>, then a
46.2278 + * <code>List</code> of <code>Locale</code>s:
46.2279 + * <pre>
46.2280 + * Locale("ja", "", "XX")
46.2281 + * Locale("ja")
46.2282 + * Locale.ROOT
46.2283 + * </pre>
46.2284 + * is returned. And if the resource bundles for the "ja" and
46.2285 + * "" <code>Locale</code>s are found, then the runtime resource
46.2286 + * lookup path (parent chain) is:
46.2287 + * <pre>
46.2288 + * Messages_ja -> Messages
46.2289 + * </pre>
46.2290 + *
46.2291 + * @param baseName
46.2292 + * the base name of the resource bundle, a fully
46.2293 + * qualified class name
46.2294 + * @param locale
46.2295 + * the locale for which a resource bundle is desired
46.2296 + * @return a <code>List</code> of candidate
46.2297 + * <code>Locale</code>s for the given <code>locale</code>
46.2298 + * @exception NullPointerException
46.2299 + * if <code>baseName</code> or <code>locale</code> is
46.2300 + * <code>null</code>
46.2301 + */
46.2302 + public List<Locale> getCandidateLocales(String baseName, Locale locale) {
46.2303 + if (baseName == null) {
46.2304 + throw new NullPointerException();
46.2305 + }
46.2306 + return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
46.2307 + }
46.2308 +
46.2309 + private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
46.2310 +
46.2311 + private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
46.2312 + protected List<Locale> createObject(BaseLocale base) {
46.2313 + String language = base.getLanguage();
46.2314 + String script = base.getScript();
46.2315 + String region = base.getRegion();
46.2316 + String variant = base.getVariant();
46.2317 +
46.2318 + // Special handling for Norwegian
46.2319 + boolean isNorwegianBokmal = false;
46.2320 + boolean isNorwegianNynorsk = false;
46.2321 + if (language.equals("no")) {
46.2322 + if (region.equals("NO") && variant.equals("NY")) {
46.2323 + variant = "";
46.2324 + isNorwegianNynorsk = true;
46.2325 + } else {
46.2326 + isNorwegianBokmal = true;
46.2327 + }
46.2328 + }
46.2329 + if (language.equals("nb") || isNorwegianBokmal) {
46.2330 + List<Locale> tmpList = getDefaultList("nb", script, region, variant);
46.2331 + // Insert a locale replacing "nb" with "no" for every list entry
46.2332 + List<Locale> bokmalList = new LinkedList<>();
46.2333 + for (Locale l : tmpList) {
46.2334 + bokmalList.add(l);
46.2335 + if (l.getLanguage().length() == 0) {
46.2336 + break;
46.2337 + }
46.2338 + bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
46.2339 + l.getVariant(), null));
46.2340 + }
46.2341 + return bokmalList;
46.2342 + } else if (language.equals("nn") || isNorwegianNynorsk) {
46.2343 + // Insert no_NO_NY, no_NO, no after nn
46.2344 + List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
46.2345 + int idx = nynorskList.size() - 1;
46.2346 + nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
46.2347 + nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
46.2348 + nynorskList.add(idx++, Locale.getInstance("no", "", ""));
46.2349 + return nynorskList;
46.2350 + }
46.2351 + // Special handling for Chinese
46.2352 + else if (language.equals("zh")) {
46.2353 + if (script.length() == 0 && region.length() > 0) {
46.2354 + // Supply script for users who want to use zh_Hans/zh_Hant
46.2355 + // as bundle names (recommended for Java7+)
46.2356 + if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
46.2357 + script = "Hant";
46.2358 + } else if (region.equals("CN") || region.equals("SG")) {
46.2359 + script = "Hans";
46.2360 + }
46.2361 + } else if (script.length() > 0 && region.length() == 0) {
46.2362 + // Supply region(country) for users who still package Chinese
46.2363 + // bundles using old convension.
46.2364 + if (script.equals("Hans")) {
46.2365 + region = "CN";
46.2366 + } else if (script.equals("Hant")) {
46.2367 + region = "TW";
46.2368 + }
46.2369 + }
46.2370 + }
46.2371 +
46.2372 + return getDefaultList(language, script, region, variant);
46.2373 + }
46.2374 +
46.2375 + private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
46.2376 + List<String> variants = null;
46.2377 +
46.2378 + if (variant.length() > 0) {
46.2379 + variants = new LinkedList<>();
46.2380 + int idx = variant.length();
46.2381 + while (idx != -1) {
46.2382 + variants.add(variant.substring(0, idx));
46.2383 + idx = variant.lastIndexOf('_', --idx);
46.2384 + }
46.2385 + }
46.2386 +
46.2387 + List<Locale> list = new LinkedList<>();
46.2388 +
46.2389 + if (variants != null) {
46.2390 + for (String v : variants) {
46.2391 + list.add(Locale.getInstance(language, script, region, v, null));
46.2392 + }
46.2393 + }
46.2394 + if (region.length() > 0) {
46.2395 + list.add(Locale.getInstance(language, script, region, "", null));
46.2396 + }
46.2397 + if (script.length() > 0) {
46.2398 + list.add(Locale.getInstance(language, script, "", "", null));
46.2399 +
46.2400 + // With script, after truncating variant, region and script,
46.2401 + // start over without script.
46.2402 + if (variants != null) {
46.2403 + for (String v : variants) {
46.2404 + list.add(Locale.getInstance(language, "", region, v, null));
46.2405 + }
46.2406 + }
46.2407 + if (region.length() > 0) {
46.2408 + list.add(Locale.getInstance(language, "", region, "", null));
46.2409 + }
46.2410 + }
46.2411 + if (language.length() > 0) {
46.2412 + list.add(Locale.getInstance(language, "", "", "", null));
46.2413 + }
46.2414 + // Add root locale at the end
46.2415 + list.add(Locale.ROOT);
46.2416 +
46.2417 + return list;
46.2418 + }
46.2419 + }
46.2420 +
46.2421 + /**
46.2422 + * Returns a <code>Locale</code> to be used as a fallback locale for
46.2423 + * further resource bundle searches by the
46.2424 + * <code>ResourceBundle.getBundle</code> factory method. This method
46.2425 + * is called from the factory method every time when no resulting
46.2426 + * resource bundle has been found for <code>baseName</code> and
46.2427 + * <code>locale</code>, where locale is either the parameter for
46.2428 + * <code>ResourceBundle.getBundle</code> or the previous fallback
46.2429 + * locale returned by this method.
46.2430 + *
46.2431 + * <p>The method returns <code>null</code> if no further fallback
46.2432 + * search is desired.
46.2433 + *
46.2434 + * <p>The default implementation returns the {@linkplain
46.2435 + * Locale#getDefault() default <code>Locale</code>} if the given
46.2436 + * <code>locale</code> isn't the default one. Otherwise,
46.2437 + * <code>null</code> is returned.
46.2438 + *
46.2439 + * @param baseName
46.2440 + * the base name of the resource bundle, a fully
46.2441 + * qualified class name for which
46.2442 + * <code>ResourceBundle.getBundle</code> has been
46.2443 + * unable to find any resource bundles (except for the
46.2444 + * base bundle)
46.2445 + * @param locale
46.2446 + * the <code>Locale</code> for which
46.2447 + * <code>ResourceBundle.getBundle</code> has been
46.2448 + * unable to find any resource bundles (except for the
46.2449 + * base bundle)
46.2450 + * @return a <code>Locale</code> for the fallback search,
46.2451 + * or <code>null</code> if no further fallback search
46.2452 + * is desired.
46.2453 + * @exception NullPointerException
46.2454 + * if <code>baseName</code> or <code>locale</code>
46.2455 + * is <code>null</code>
46.2456 + */
46.2457 + public Locale getFallbackLocale(String baseName, Locale locale) {
46.2458 + if (baseName == null) {
46.2459 + throw new NullPointerException();
46.2460 + }
46.2461 + Locale defaultLocale = Locale.getDefault();
46.2462 + return locale.equals(defaultLocale) ? null : defaultLocale;
46.2463 + }
46.2464 +
46.2465 + /**
46.2466 + * Instantiates a resource bundle for the given bundle name of the
46.2467 + * given format and locale, using the given class loader if
46.2468 + * necessary. This method returns <code>null</code> if there is no
46.2469 + * resource bundle available for the given parameters. If a resource
46.2470 + * bundle can't be instantiated due to an unexpected error, the
46.2471 + * error must be reported by throwing an <code>Error</code> or
46.2472 + * <code>Exception</code> rather than simply returning
46.2473 + * <code>null</code>.
46.2474 + *
46.2475 + * <p>If the <code>reload</code> flag is <code>true</code>, it
46.2476 + * indicates that this method is being called because the previously
46.2477 + * loaded resource bundle has expired.
46.2478 + *
46.2479 + * <p>The default implementation instantiates a
46.2480 + * <code>ResourceBundle</code> as follows.
46.2481 + *
46.2482 + * <ul>
46.2483 + *
46.2484 + * <li>The bundle name is obtained by calling {@link
46.2485 + * #toBundleName(String, Locale) toBundleName(baseName,
46.2486 + * locale)}.</li>
46.2487 + *
46.2488 + * <li>If <code>format</code> is <code>"java.class"</code>, the
46.2489 + * {@link Class} specified by the bundle name is loaded by calling
46.2490 + * {@link ClassLoader#loadClass(String)}. Then, a
46.2491 + * <code>ResourceBundle</code> is instantiated by calling {@link
46.2492 + * Class#newInstance()}. Note that the <code>reload</code> flag is
46.2493 + * ignored for loading class-based resource bundles in this default
46.2494 + * implementation.</li>
46.2495 + *
46.2496 + * <li>If <code>format</code> is <code>"java.properties"</code>,
46.2497 + * {@link #toResourceName(String, String) toResourceName(bundlename,
46.2498 + * "properties")} is called to get the resource name.
46.2499 + * If <code>reload</code> is <code>true</code>, {@link
46.2500 + * ClassLoader#getResource(String) load.getResource} is called
46.2501 + * to get a {@link URL} for creating a {@link
46.2502 + * URLConnection}. This <code>URLConnection</code> is used to
46.2503 + * {@linkplain URLConnection#setUseCaches(boolean) disable the
46.2504 + * caches} of the underlying resource loading layers,
46.2505 + * and to {@linkplain URLConnection#getInputStream() get an
46.2506 + * <code>InputStream</code>}.
46.2507 + * Otherwise, {@link ClassLoader#getResourceAsStream(String)
46.2508 + * loader.getResourceAsStream} is called to get an {@link
46.2509 + * InputStream}. Then, a {@link
46.2510 + * PropertyResourceBundle} is constructed with the
46.2511 + * <code>InputStream</code>.</li>
46.2512 + *
46.2513 + * <li>If <code>format</code> is neither <code>"java.class"</code>
46.2514 + * nor <code>"java.properties"</code>, an
46.2515 + * <code>IllegalArgumentException</code> is thrown.</li>
46.2516 + *
46.2517 + * </ul>
46.2518 + *
46.2519 + * @param baseName
46.2520 + * the base bundle name of the resource bundle, a fully
46.2521 + * qualified class name
46.2522 + * @param locale
46.2523 + * the locale for which the resource bundle should be
46.2524 + * instantiated
46.2525 + * @param format
46.2526 + * the resource bundle format to be loaded
46.2527 + * @param loader
46.2528 + * the <code>ClassLoader</code> to use to load the bundle
46.2529 + * @param reload
46.2530 + * the flag to indicate bundle reloading; <code>true</code>
46.2531 + * if reloading an expired resource bundle,
46.2532 + * <code>false</code> otherwise
46.2533 + * @return the resource bundle instance,
46.2534 + * or <code>null</code> if none could be found.
46.2535 + * @exception NullPointerException
46.2536 + * if <code>bundleName</code>, <code>locale</code>,
46.2537 + * <code>format</code>, or <code>loader</code> is
46.2538 + * <code>null</code>, or if <code>null</code> is returned by
46.2539 + * {@link #toBundleName(String, Locale) toBundleName}
46.2540 + * @exception IllegalArgumentException
46.2541 + * if <code>format</code> is unknown, or if the resource
46.2542 + * found for the given parameters contains malformed data.
46.2543 + * @exception ClassCastException
46.2544 + * if the loaded class cannot be cast to <code>ResourceBundle</code>
46.2545 + * @exception IllegalAccessException
46.2546 + * if the class or its nullary constructor is not
46.2547 + * accessible.
46.2548 + * @exception InstantiationException
46.2549 + * if the instantiation of a class fails for some other
46.2550 + * reason.
46.2551 + * @exception ExceptionInInitializerError
46.2552 + * if the initialization provoked by this method fails.
46.2553 + * @exception SecurityException
46.2554 + * If a security manager is present and creation of new
46.2555 + * instances is denied. See {@link Class#newInstance()}
46.2556 + * for details.
46.2557 + * @exception IOException
46.2558 + * if an error occurred when reading resources using
46.2559 + * any I/O operations
46.2560 + */
46.2561 + public ResourceBundle newBundle(String baseName, Locale locale, String format,
46.2562 + ClassLoader loader, boolean reload)
46.2563 + throws IllegalAccessException, InstantiationException, IOException {
46.2564 + String bundleName = toBundleName(baseName, locale);
46.2565 + ResourceBundle bundle = null;
46.2566 + if (format.equals("java.class")) {
46.2567 + try {
46.2568 + Class<? extends ResourceBundle> bundleClass
46.2569 + = (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
46.2570 +
46.2571 + // If the class isn't a ResourceBundle subclass, throw a
46.2572 + // ClassCastException.
46.2573 + if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
46.2574 + bundle = bundleClass.newInstance();
46.2575 + } else {
46.2576 + throw new ClassCastException(bundleClass.getName()
46.2577 + + " cannot be cast to ResourceBundle");
46.2578 + }
46.2579 + } catch (ClassNotFoundException e) {
46.2580 + }
46.2581 + } else if (format.equals("java.properties")) {
46.2582 + final String resourceName = toResourceName(bundleName, "properties");
46.2583 + final ClassLoader classLoader = loader;
46.2584 + final boolean reloadFlag = reload;
46.2585 + InputStream stream = null;
46.2586 + try {
46.2587 + stream = AccessController.doPrivileged(
46.2588 + new PrivilegedExceptionAction<InputStream>() {
46.2589 + public InputStream run() throws IOException {
46.2590 + InputStream is = null;
46.2591 + if (reloadFlag) {
46.2592 + URL url = classLoader.getResource(resourceName);
46.2593 + if (url != null) {
46.2594 + URLConnection connection = url.openConnection();
46.2595 + if (connection != null) {
46.2596 + // Disable caches to get fresh data for
46.2597 + // reloading.
46.2598 + connection.setUseCaches(false);
46.2599 + is = connection.getInputStream();
46.2600 + }
46.2601 + }
46.2602 + } else {
46.2603 + is = classLoader.getResourceAsStream(resourceName);
46.2604 + }
46.2605 + return is;
46.2606 + }
46.2607 + });
46.2608 + } catch (PrivilegedActionException e) {
46.2609 + throw (IOException) e.getException();
46.2610 + }
46.2611 + if (stream != null) {
46.2612 + try {
46.2613 + bundle = new PropertyResourceBundle(stream);
46.2614 + } finally {
46.2615 + stream.close();
46.2616 + }
46.2617 + }
46.2618 + } else {
46.2619 + throw new IllegalArgumentException("unknown format: " + format);
46.2620 + }
46.2621 + return bundle;
46.2622 + }
46.2623 +
46.2624 + /**
46.2625 + * Returns the time-to-live (TTL) value for resource bundles that
46.2626 + * are loaded under this
46.2627 + * <code>ResourceBundle.Control</code>. Positive time-to-live values
46.2628 + * specify the number of milliseconds a bundle can remain in the
46.2629 + * cache without being validated against the source data from which
46.2630 + * it was constructed. The value 0 indicates that a bundle must be
46.2631 + * validated each time it is retrieved from the cache. {@link
46.2632 + * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
46.2633 + * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
46.2634 + * that loaded resource bundles are put in the cache with no
46.2635 + * expiration control.
46.2636 + *
46.2637 + * <p>The expiration affects only the bundle loading process by the
46.2638 + * <code>ResourceBundle.getBundle</code> factory method. That is,
46.2639 + * if the factory method finds a resource bundle in the cache that
46.2640 + * has expired, the factory method calls the {@link
46.2641 + * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
46.2642 + * long) needsReload} method to determine whether the resource
46.2643 + * bundle needs to be reloaded. If <code>needsReload</code> returns
46.2644 + * <code>true</code>, the cached resource bundle instance is removed
46.2645 + * from the cache. Otherwise, the instance stays in the cache,
46.2646 + * updated with the new TTL value returned by this method.
46.2647 + *
46.2648 + * <p>All cached resource bundles are subject to removal from the
46.2649 + * cache due to memory constraints of the runtime environment.
46.2650 + * Returning a large positive value doesn't mean to lock loaded
46.2651 + * resource bundles in the cache.
46.2652 + *
46.2653 + * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
46.2654 + *
46.2655 + * @param baseName
46.2656 + * the base name of the resource bundle for which the
46.2657 + * expiration value is specified.
46.2658 + * @param locale
46.2659 + * the locale of the resource bundle for which the
46.2660 + * expiration value is specified.
46.2661 + * @return the time (0 or a positive millisecond offset from the
46.2662 + * cached time) to get loaded bundles expired in the cache,
46.2663 + * {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
46.2664 + * expiration control, or {@link #TTL_DONT_CACHE} to disable
46.2665 + * caching.
46.2666 + * @exception NullPointerException
46.2667 + * if <code>baseName</code> or <code>locale</code> is
46.2668 + * <code>null</code>
46.2669 + */
46.2670 + public long getTimeToLive(String baseName, Locale locale) {
46.2671 + if (baseName == null || locale == null) {
46.2672 + throw new NullPointerException();
46.2673 + }
46.2674 + return TTL_NO_EXPIRATION_CONTROL;
46.2675 + }
46.2676 +
46.2677 + /**
46.2678 + * Determines if the expired <code>bundle</code> in the cache needs
46.2679 + * to be reloaded based on the loading time given by
46.2680 + * <code>loadTime</code> or some other criteria. The method returns
46.2681 + * <code>true</code> if reloading is required; <code>false</code>
46.2682 + * otherwise. <code>loadTime</code> is a millisecond offset since
46.2683 + * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
46.2684 + * Epoch</a>.
46.2685 + *
46.2686 + * The calling <code>ResourceBundle.getBundle</code> factory method
46.2687 + * calls this method on the <code>ResourceBundle.Control</code>
46.2688 + * instance used for its current invocation, not on the instance
46.2689 + * used in the invocation that originally loaded the resource
46.2690 + * bundle.
46.2691 + *
46.2692 + * <p>The default implementation compares <code>loadTime</code> and
46.2693 + * the last modified time of the source data of the resource
46.2694 + * bundle. If it's determined that the source data has been modified
46.2695 + * since <code>loadTime</code>, <code>true</code> is
46.2696 + * returned. Otherwise, <code>false</code> is returned. This
46.2697 + * implementation assumes that the given <code>format</code> is the
46.2698 + * same string as its file suffix if it's not one of the default
46.2699 + * formats, <code>"java.class"</code> or
46.2700 + * <code>"java.properties"</code>.
46.2701 + *
46.2702 + * @param baseName
46.2703 + * the base bundle name of the resource bundle, a
46.2704 + * fully qualified class name
46.2705 + * @param locale
46.2706 + * the locale for which the resource bundle
46.2707 + * should be instantiated
46.2708 + * @param format
46.2709 + * the resource bundle format to be loaded
46.2710 + * @param loader
46.2711 + * the <code>ClassLoader</code> to use to load the bundle
46.2712 + * @param bundle
46.2713 + * the resource bundle instance that has been expired
46.2714 + * in the cache
46.2715 + * @param loadTime
46.2716 + * the time when <code>bundle</code> was loaded and put
46.2717 + * in the cache
46.2718 + * @return <code>true</code> if the expired bundle needs to be
46.2719 + * reloaded; <code>false</code> otherwise.
46.2720 + * @exception NullPointerException
46.2721 + * if <code>baseName</code>, <code>locale</code>,
46.2722 + * <code>format</code>, <code>loader</code>, or
46.2723 + * <code>bundle</code> is <code>null</code>
46.2724 + */
46.2725 + public boolean needsReload(String baseName, Locale locale,
46.2726 + String format, ClassLoader loader,
46.2727 + ResourceBundle bundle, long loadTime) {
46.2728 + if (bundle == null) {
46.2729 + throw new NullPointerException();
46.2730 + }
46.2731 + if (format.equals("java.class") || format.equals("java.properties")) {
46.2732 + format = format.substring(5);
46.2733 + }
46.2734 + boolean result = false;
46.2735 + try {
46.2736 + String resourceName = toResourceName(toBundleName(baseName, locale), format);
46.2737 + URL url = loader.getResource(resourceName);
46.2738 + if (url != null) {
46.2739 + long lastModified = 0;
46.2740 + URLConnection connection = url.openConnection();
46.2741 + if (connection != null) {
46.2742 + // disable caches to get the correct data
46.2743 + connection.setUseCaches(false);
46.2744 + if (connection instanceof JarURLConnection) {
46.2745 + JarEntry ent = ((JarURLConnection)connection).getJarEntry();
46.2746 + if (ent != null) {
46.2747 + lastModified = ent.getTime();
46.2748 + if (lastModified == -1) {
46.2749 + lastModified = 0;
46.2750 + }
46.2751 + }
46.2752 + } else {
46.2753 + lastModified = connection.getLastModified();
46.2754 + }
46.2755 + }
46.2756 + result = lastModified >= loadTime;
46.2757 + }
46.2758 + } catch (NullPointerException npe) {
46.2759 + throw npe;
46.2760 + } catch (Exception e) {
46.2761 + // ignore other exceptions
46.2762 + }
46.2763 + return result;
46.2764 + }
46.2765 +
46.2766 + /**
46.2767 + * Converts the given <code>baseName</code> and <code>locale</code>
46.2768 + * to the bundle name. This method is called from the default
46.2769 + * implementation of the {@link #newBundle(String, Locale, String,
46.2770 + * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
46.2771 + * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
46.2772 + * methods.
46.2773 + *
46.2774 + * <p>This implementation returns the following value:
46.2775 + * <pre>
46.2776 + * baseName + "_" + language + "_" + script + "_" + country + "_" + variant
46.2777 + * </pre>
46.2778 + * where <code>language</code>, <code>script</code>, <code>country</code>,
46.2779 + * and <code>variant</code> are the language, script, country, and variant
46.2780 + * values of <code>locale</code>, respectively. Final component values that
46.2781 + * are empty Strings are omitted along with the preceding '_'. When the
46.2782 + * script is empty, the script value is ommitted along with the preceding '_'.
46.2783 + * If all of the values are empty strings, then <code>baseName</code>
46.2784 + * is returned.
46.2785 + *
46.2786 + * <p>For example, if <code>baseName</code> is
46.2787 + * <code>"baseName"</code> and <code>locale</code> is
46.2788 + * <code>Locale("ja", "", "XX")</code>, then
46.2789 + * <code>"baseName_ja_ _XX"</code> is returned. If the given
46.2790 + * locale is <code>Locale("en")</code>, then
46.2791 + * <code>"baseName_en"</code> is returned.
46.2792 + *
46.2793 + * <p>Overriding this method allows applications to use different
46.2794 + * conventions in the organization and packaging of localized
46.2795 + * resources.
46.2796 + *
46.2797 + * @param baseName
46.2798 + * the base name of the resource bundle, a fully
46.2799 + * qualified class name
46.2800 + * @param locale
46.2801 + * the locale for which a resource bundle should be
46.2802 + * loaded
46.2803 + * @return the bundle name for the resource bundle
46.2804 + * @exception NullPointerException
46.2805 + * if <code>baseName</code> or <code>locale</code>
46.2806 + * is <code>null</code>
46.2807 + */
46.2808 + public String toBundleName(String baseName, Locale locale) {
46.2809 + if (locale == Locale.ROOT) {
46.2810 + return baseName;
46.2811 + }
46.2812 +
46.2813 + String language = locale.getLanguage();
46.2814 + String script = locale.getScript();
46.2815 + String country = locale.getCountry();
46.2816 + String variant = locale.getVariant();
46.2817 +
46.2818 + if (language == "" && country == "" && variant == "") {
46.2819 + return baseName;
46.2820 + }
46.2821 +
46.2822 + StringBuilder sb = new StringBuilder(baseName);
46.2823 + sb.append('_');
46.2824 + if (script != "") {
46.2825 + if (variant != "") {
46.2826 + sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
46.2827 + } else if (country != "") {
46.2828 + sb.append(language).append('_').append(script).append('_').append(country);
46.2829 + } else {
46.2830 + sb.append(language).append('_').append(script);
46.2831 + }
46.2832 + } else {
46.2833 + if (variant != "") {
46.2834 + sb.append(language).append('_').append(country).append('_').append(variant);
46.2835 + } else if (country != "") {
46.2836 + sb.append(language).append('_').append(country);
46.2837 + } else {
46.2838 + sb.append(language);
46.2839 + }
46.2840 + }
46.2841 + return sb.toString();
46.2842 +
46.2843 + }
46.2844 +
46.2845 + /**
46.2846 + * Converts the given <code>bundleName</code> to the form required
46.2847 + * by the {@link ClassLoader#getResource ClassLoader.getResource}
46.2848 + * method by replacing all occurrences of <code>'.'</code> in
46.2849 + * <code>bundleName</code> with <code>'/'</code> and appending a
46.2850 + * <code>'.'</code> and the given file <code>suffix</code>. For
46.2851 + * example, if <code>bundleName</code> is
46.2852 + * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code>
46.2853 + * is <code>"properties"</code>, then
46.2854 + * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned.
46.2855 + *
46.2856 + * @param bundleName
46.2857 + * the bundle name
46.2858 + * @param suffix
46.2859 + * the file type suffix
46.2860 + * @return the converted resource name
46.2861 + * @exception NullPointerException
46.2862 + * if <code>bundleName</code> or <code>suffix</code>
46.2863 + * is <code>null</code>
46.2864 + */
46.2865 + public final String toResourceName(String bundleName, String suffix) {
46.2866 + StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
46.2867 + sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
46.2868 + return sb.toString();
46.2869 + }
46.2870 + }
46.2871 +
46.2872 + private static class SingleFormatControl extends Control {
46.2873 + private static final Control PROPERTIES_ONLY
46.2874 + = new SingleFormatControl(FORMAT_PROPERTIES);
46.2875 +
46.2876 + private static final Control CLASS_ONLY
46.2877 + = new SingleFormatControl(FORMAT_CLASS);
46.2878 +
46.2879 + private final List<String> formats;
46.2880 +
46.2881 + protected SingleFormatControl(List<String> formats) {
46.2882 + this.formats = formats;
46.2883 + }
46.2884 +
46.2885 + public List<String> getFormats(String baseName) {
46.2886 + if (baseName == null) {
46.2887 + throw new NullPointerException();
46.2888 + }
46.2889 + return formats;
46.2890 + }
46.2891 + }
46.2892 +
46.2893 + private static final class NoFallbackControl extends SingleFormatControl {
46.2894 + private static final Control NO_FALLBACK
46.2895 + = new NoFallbackControl(FORMAT_DEFAULT);
46.2896 +
46.2897 + private static final Control PROPERTIES_ONLY_NO_FALLBACK
46.2898 + = new NoFallbackControl(FORMAT_PROPERTIES);
46.2899 +
46.2900 + private static final Control CLASS_ONLY_NO_FALLBACK
46.2901 + = new NoFallbackControl(FORMAT_CLASS);
46.2902 +
46.2903 + protected NoFallbackControl(List<String> formats) {
46.2904 + super(formats);
46.2905 + }
46.2906 +
46.2907 + public Locale getFallbackLocale(String baseName, Locale locale) {
46.2908 + if (baseName == null || locale == null) {
46.2909 + throw new NullPointerException();
46.2910 + }
46.2911 + return null;
46.2912 + }
46.2913 + }
46.2914 +}
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/rt/emul/compact/src/main/java/java/util/SimpleTimeZone.java Thu Oct 03 15:40:35 2013 +0200
47.3 @@ -0,0 +1,1706 @@
47.4 +/*
47.5 + * Copyright (c) 1996, 2011, 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 +/*
47.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
47.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
47.32 + *
47.33 + * The original version of this source code and documentation is copyrighted
47.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
47.35 + * materials are provided under terms of a License Agreement between Taligent
47.36 + * and Sun. This technology is protected by multiple US and International
47.37 + * patents. This notice and attribution to Taligent may not be removed.
47.38 + * Taligent is a registered trademark of Taligent, Inc.
47.39 + *
47.40 + */
47.41 +
47.42 +package java.util;
47.43 +
47.44 +import java.io.ObjectInputStream;
47.45 +import java.io.ObjectOutputStream;
47.46 +import java.io.IOException;
47.47 +import sun.util.calendar.CalendarSystem;
47.48 +import sun.util.calendar.CalendarUtils;
47.49 +import sun.util.calendar.BaseCalendar;
47.50 +import sun.util.calendar.Gregorian;
47.51 +
47.52 +/**
47.53 + * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
47.54 + * that represents a time zone for use with a Gregorian calendar.
47.55 + * The class holds an offset from GMT, called <em>raw offset</em>, and start
47.56 + * and end rules for a daylight saving time schedule. Since it only holds
47.57 + * single values for each, it cannot handle historical changes in the offset
47.58 + * from GMT and the daylight saving schedule, except that the {@link
47.59 + * #setStartYear setStartYear} method can specify the year when the daylight
47.60 + * saving time schedule starts in effect.
47.61 + * <p>
47.62 + * To construct a <code>SimpleTimeZone</code> with a daylight saving time
47.63 + * schedule, the schedule can be described with a set of rules,
47.64 + * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
47.65 + * starts or ends is specified by a combination of <em>month</em>,
47.66 + * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
47.67 + * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
47.68 + * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
47.69 + * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
47.70 + * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
47.71 + * are as follows.
47.72 + *
47.73 + * <ul>
47.74 + * <li><b>Exact day of month</b><br>
47.75 + * To specify an exact day of month, set the <em>month</em> and
47.76 + * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
47.77 + * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
47.78 + * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
47.79 + *
47.80 + * <li><b>Day of week on or after day of month</b><br>
47.81 + * To specify a day of week on or after an exact day of month, set the
47.82 + * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
47.83 + * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
47.84 + * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
47.85 + * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
47.86 + * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
47.87 + * Calendar#SUNDAY SUNDAY}.</li>
47.88 + *
47.89 + * <li><b>Day of week on or before day of month</b><br>
47.90 + * To specify a day of the week on or before an exact day of the month, set
47.91 + * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
47.92 + * example, to specify the last Wednesday on or before the 21st of March, set
47.93 + * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
47.94 + * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
47.95 + *
47.96 + * <li><b>Last day-of-week of month</b><br>
47.97 + * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
47.98 + * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
47.99 + * -1. For example, to specify the last Sunday of October, set <em>month</em>
47.100 + * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
47.101 + * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1. </li>
47.102 + *
47.103 + * </ul>
47.104 + * The time of the day at which daylight saving time starts or ends is
47.105 + * specified by a millisecond value within the day. There are three kinds of
47.106 + * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
47.107 + * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
47.108 + * saving time ends
47.109 + * at 2:00 am in the wall clock time, it can be specified by 7200000
47.110 + * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
47.111 + * for an <em>end-rule</em> means the same thing as the daylight time.
47.112 + * <p>
47.113 + * The following are examples of parameters for constructing time zone objects.
47.114 + * <pre><code>
47.115 + * // Base GMT offset: -8:00
47.116 + * // DST starts: at 2:00am in standard time
47.117 + * // on the first Sunday in April
47.118 + * // DST ends: at 2:00am in daylight time
47.119 + * // on the last Sunday in October
47.120 + * // Save: 1 hour
47.121 + * SimpleTimeZone(-28800000,
47.122 + * "America/Los_Angeles",
47.123 + * Calendar.APRIL, 1, -Calendar.SUNDAY,
47.124 + * 7200000,
47.125 + * Calendar.OCTOBER, -1, Calendar.SUNDAY,
47.126 + * 7200000,
47.127 + * 3600000)
47.128 + *
47.129 + * // Base GMT offset: +1:00
47.130 + * // DST starts: at 1:00am in UTC time
47.131 + * // on the last Sunday in March
47.132 + * // DST ends: at 1:00am in UTC time
47.133 + * // on the last Sunday in October
47.134 + * // Save: 1 hour
47.135 + * SimpleTimeZone(3600000,
47.136 + * "Europe/Paris",
47.137 + * Calendar.MARCH, -1, Calendar.SUNDAY,
47.138 + * 3600000, SimpleTimeZone.UTC_TIME,
47.139 + * Calendar.OCTOBER, -1, Calendar.SUNDAY,
47.140 + * 3600000, SimpleTimeZone.UTC_TIME,
47.141 + * 3600000)
47.142 + * </code></pre>
47.143 + * These parameter rules are also applicable to the set rule methods, such as
47.144 + * <code>setStartRule</code>.
47.145 + *
47.146 + * @since 1.1
47.147 + * @see Calendar
47.148 + * @see GregorianCalendar
47.149 + * @see TimeZone
47.150 + * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
47.151 + */
47.152 +
47.153 +public class SimpleTimeZone extends TimeZone {
47.154 + /**
47.155 + * Constructs a SimpleTimeZone with the given base time zone offset from GMT
47.156 + * and time zone ID with no daylight saving time schedule.
47.157 + *
47.158 + * @param rawOffset The base time zone offset in milliseconds to GMT.
47.159 + * @param ID The time zone name that is given to this instance.
47.160 + */
47.161 + public SimpleTimeZone(int rawOffset, String ID)
47.162 + {
47.163 + this.rawOffset = rawOffset;
47.164 + setID (ID);
47.165 + dstSavings = millisPerHour; // In case user sets rules later
47.166 + }
47.167 +
47.168 + /**
47.169 + * Constructs a SimpleTimeZone with the given base time zone offset from
47.170 + * GMT, time zone ID, and rules for starting and ending the daylight
47.171 + * time.
47.172 + * Both <code>startTime</code> and <code>endTime</code> are specified to be
47.173 + * represented in the wall clock time. The amount of daylight saving is
47.174 + * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
47.175 + * equivalent to:
47.176 + * <pre><code>
47.177 + * SimpleTimeZone(rawOffset,
47.178 + * ID,
47.179 + * startMonth,
47.180 + * startDay,
47.181 + * startDayOfWeek,
47.182 + * startTime,
47.183 + * SimpleTimeZone.{@link #WALL_TIME},
47.184 + * endMonth,
47.185 + * endDay,
47.186 + * endDayOfWeek,
47.187 + * endTime,
47.188 + * SimpleTimeZone.{@link #WALL_TIME},
47.189 + * 3600000)
47.190 + * </code></pre>
47.191 + *
47.192 + * @param rawOffset The given base time zone offset from GMT.
47.193 + * @param ID The time zone ID which is given to this object.
47.194 + * @param startMonth The daylight saving time starting month. Month is
47.195 + * a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
47.196 + * for January).
47.197 + * @param startDay The day of the month on which the daylight saving time starts.
47.198 + * See the class description for the special cases of this parameter.
47.199 + * @param startDayOfWeek The daylight saving time starting day-of-week.
47.200 + * See the class description for the special cases of this parameter.
47.201 + * @param startTime The daylight saving time starting time in local wall clock
47.202 + * time (in milliseconds within the day), which is local
47.203 + * standard time in this case.
47.204 + * @param endMonth The daylight saving time ending month. Month is
47.205 + * a {@link Calendar#MONTH MONTH} field
47.206 + * value (0-based. e.g., 9 for October).
47.207 + * @param endDay The day of the month on which the daylight saving time ends.
47.208 + * See the class description for the special cases of this parameter.
47.209 + * @param endDayOfWeek The daylight saving time ending day-of-week.
47.210 + * See the class description for the special cases of this parameter.
47.211 + * @param endTime The daylight saving ending time in local wall clock time,
47.212 + * (in milliseconds within the day) which is local daylight
47.213 + * time in this case.
47.214 + * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
47.215 + * parameters are out of range for the start or end rule
47.216 + */
47.217 + public SimpleTimeZone(int rawOffset, String ID,
47.218 + int startMonth, int startDay, int startDayOfWeek, int startTime,
47.219 + int endMonth, int endDay, int endDayOfWeek, int endTime)
47.220 + {
47.221 + this(rawOffset, ID,
47.222 + startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
47.223 + endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
47.224 + millisPerHour);
47.225 + }
47.226 +
47.227 + /**
47.228 + * Constructs a SimpleTimeZone with the given base time zone offset from
47.229 + * GMT, time zone ID, and rules for starting and ending the daylight
47.230 + * time.
47.231 + * Both <code>startTime</code> and <code>endTime</code> are assumed to be
47.232 + * represented in the wall clock time. This constructor is equivalent to:
47.233 + * <pre><code>
47.234 + * SimpleTimeZone(rawOffset,
47.235 + * ID,
47.236 + * startMonth,
47.237 + * startDay,
47.238 + * startDayOfWeek,
47.239 + * startTime,
47.240 + * SimpleTimeZone.{@link #WALL_TIME},
47.241 + * endMonth,
47.242 + * endDay,
47.243 + * endDayOfWeek,
47.244 + * endTime,
47.245 + * SimpleTimeZone.{@link #WALL_TIME},
47.246 + * dstSavings)
47.247 + * </code></pre>
47.248 + *
47.249 + * @param rawOffset The given base time zone offset from GMT.
47.250 + * @param ID The time zone ID which is given to this object.
47.251 + * @param startMonth The daylight saving time starting month. Month is
47.252 + * a {@link Calendar#MONTH MONTH} field
47.253 + * value (0-based. e.g., 0 for January).
47.254 + * @param startDay The day of the month on which the daylight saving time starts.
47.255 + * See the class description for the special cases of this parameter.
47.256 + * @param startDayOfWeek The daylight saving time starting day-of-week.
47.257 + * See the class description for the special cases of this parameter.
47.258 + * @param startTime The daylight saving time starting time in local wall clock
47.259 + * time, which is local standard time in this case.
47.260 + * @param endMonth The daylight saving time ending month. Month is
47.261 + * a {@link Calendar#MONTH MONTH} field
47.262 + * value (0-based. e.g., 9 for October).
47.263 + * @param endDay The day of the month on which the daylight saving time ends.
47.264 + * See the class description for the special cases of this parameter.
47.265 + * @param endDayOfWeek The daylight saving time ending day-of-week.
47.266 + * See the class description for the special cases of this parameter.
47.267 + * @param endTime The daylight saving ending time in local wall clock time,
47.268 + * which is local daylight time in this case.
47.269 + * @param dstSavings The amount of time in milliseconds saved during
47.270 + * daylight saving time.
47.271 + * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
47.272 + * parameters are out of range for the start or end rule
47.273 + * @since 1.2
47.274 + */
47.275 + public SimpleTimeZone(int rawOffset, String ID,
47.276 + int startMonth, int startDay, int startDayOfWeek, int startTime,
47.277 + int endMonth, int endDay, int endDayOfWeek, int endTime,
47.278 + int dstSavings)
47.279 + {
47.280 + this(rawOffset, ID,
47.281 + startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
47.282 + endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
47.283 + dstSavings);
47.284 + }
47.285 +
47.286 + /**
47.287 + * Constructs a SimpleTimeZone with the given base time zone offset from
47.288 + * GMT, time zone ID, and rules for starting and ending the daylight
47.289 + * time.
47.290 + * This constructor takes the full set of the start and end rules
47.291 + * parameters, including modes of <code>startTime</code> and
47.292 + * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
47.293 + * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
47.294 + * time}.
47.295 + *
47.296 + * @param rawOffset The given base time zone offset from GMT.
47.297 + * @param ID The time zone ID which is given to this object.
47.298 + * @param startMonth The daylight saving time starting month. Month is
47.299 + * a {@link Calendar#MONTH MONTH} field
47.300 + * value (0-based. e.g., 0 for January).
47.301 + * @param startDay The day of the month on which the daylight saving time starts.
47.302 + * See the class description for the special cases of this parameter.
47.303 + * @param startDayOfWeek The daylight saving time starting day-of-week.
47.304 + * See the class description for the special cases of this parameter.
47.305 + * @param startTime The daylight saving time starting time in the time mode
47.306 + * specified by <code>startTimeMode</code>.
47.307 + * @param startTimeMode The mode of the start time specified by startTime.
47.308 + * @param endMonth The daylight saving time ending month. Month is
47.309 + * a {@link Calendar#MONTH MONTH} field
47.310 + * value (0-based. e.g., 9 for October).
47.311 + * @param endDay The day of the month on which the daylight saving time ends.
47.312 + * See the class description for the special cases of this parameter.
47.313 + * @param endDayOfWeek The daylight saving time ending day-of-week.
47.314 + * See the class description for the special cases of this parameter.
47.315 + * @param endTime The daylight saving ending time in time time mode
47.316 + * specified by <code>endTimeMode</code>.
47.317 + * @param endTimeMode The mode of the end time specified by endTime
47.318 + * @param dstSavings The amount of time in milliseconds saved during
47.319 + * daylight saving time.
47.320 + *
47.321 + * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
47.322 + * time parameters are out of range for the start or end rule, or if a time mode
47.323 + * value is invalid.
47.324 + *
47.325 + * @see #WALL_TIME
47.326 + * @see #STANDARD_TIME
47.327 + * @see #UTC_TIME
47.328 + *
47.329 + * @since 1.4
47.330 + */
47.331 + public SimpleTimeZone(int rawOffset, String ID,
47.332 + int startMonth, int startDay, int startDayOfWeek,
47.333 + int startTime, int startTimeMode,
47.334 + int endMonth, int endDay, int endDayOfWeek,
47.335 + int endTime, int endTimeMode,
47.336 + int dstSavings) {
47.337 +
47.338 + setID(ID);
47.339 + this.rawOffset = rawOffset;
47.340 + this.startMonth = startMonth;
47.341 + this.startDay = startDay;
47.342 + this.startDayOfWeek = startDayOfWeek;
47.343 + this.startTime = startTime;
47.344 + this.startTimeMode = startTimeMode;
47.345 + this.endMonth = endMonth;
47.346 + this.endDay = endDay;
47.347 + this.endDayOfWeek = endDayOfWeek;
47.348 + this.endTime = endTime;
47.349 + this.endTimeMode = endTimeMode;
47.350 + this.dstSavings = dstSavings;
47.351 +
47.352 + // this.useDaylight is set by decodeRules
47.353 + decodeRules();
47.354 + if (dstSavings <= 0) {
47.355 + throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
47.356 + }
47.357 + }
47.358 +
47.359 + /**
47.360 + * Sets the daylight saving time starting year.
47.361 + *
47.362 + * @param year The daylight saving starting year.
47.363 + */
47.364 + public void setStartYear(int year)
47.365 + {
47.366 + startYear = year;
47.367 + invalidateCache();
47.368 + }
47.369 +
47.370 + /**
47.371 + * Sets the daylight saving time start rule. For example, if daylight saving
47.372 + * time starts on the first Sunday in April at 2 am in local wall clock
47.373 + * time, you can set the start rule by calling:
47.374 + * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
47.375 + *
47.376 + * @param startMonth The daylight saving time starting month. Month is
47.377 + * a {@link Calendar#MONTH MONTH} field
47.378 + * value (0-based. e.g., 0 for January).
47.379 + * @param startDay The day of the month on which the daylight saving time starts.
47.380 + * See the class description for the special cases of this parameter.
47.381 + * @param startDayOfWeek The daylight saving time starting day-of-week.
47.382 + * See the class description for the special cases of this parameter.
47.383 + * @param startTime The daylight saving time starting time in local wall clock
47.384 + * time, which is local standard time in this case.
47.385 + * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
47.386 + * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
47.387 + */
47.388 + public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
47.389 + {
47.390 + this.startMonth = startMonth;
47.391 + this.startDay = startDay;
47.392 + this.startDayOfWeek = startDayOfWeek;
47.393 + this.startTime = startTime;
47.394 + startTimeMode = WALL_TIME;
47.395 + decodeStartRule();
47.396 + invalidateCache();
47.397 + }
47.398 +
47.399 + /**
47.400 + * Sets the daylight saving time start rule to a fixed date within a month.
47.401 + * This method is equivalent to:
47.402 + * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
47.403 + *
47.404 + * @param startMonth The daylight saving time starting month. Month is
47.405 + * a {@link Calendar#MONTH MONTH} field
47.406 + * value (0-based. e.g., 0 for January).
47.407 + * @param startDay The day of the month on which the daylight saving time starts.
47.408 + * @param startTime The daylight saving time starting time in local wall clock
47.409 + * time, which is local standard time in this case.
47.410 + * See the class description for the special cases of this parameter.
47.411 + * @exception IllegalArgumentException if the <code>startMonth</code>,
47.412 + * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
47.413 + * @since 1.2
47.414 + */
47.415 + public void setStartRule(int startMonth, int startDay, int startTime) {
47.416 + setStartRule(startMonth, startDay, 0, startTime);
47.417 + }
47.418 +
47.419 + /**
47.420 + * Sets the daylight saving time start rule to a weekday before or after the given date within
47.421 + * a month, e.g., the first Monday on or after the 8th.
47.422 + *
47.423 + * @param startMonth The daylight saving time starting month. Month is
47.424 + * a {@link Calendar#MONTH MONTH} field
47.425 + * value (0-based. e.g., 0 for January).
47.426 + * @param startDay The day of the month on which the daylight saving time starts.
47.427 + * @param startDayOfWeek The daylight saving time starting day-of-week.
47.428 + * @param startTime The daylight saving time starting time in local wall clock
47.429 + * time, which is local standard time in this case.
47.430 + * @param after If true, this rule selects the first <code>dayOfWeek</code> on or
47.431 + * <em>after</em> <code>dayOfMonth</code>. If false, this rule
47.432 + * selects the last <code>dayOfWeek</code> on or <em>before</em>
47.433 + * <code>dayOfMonth</code>.
47.434 + * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
47.435 + * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
47.436 + * @since 1.2
47.437 + */
47.438 + public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
47.439 + int startTime, boolean after)
47.440 + {
47.441 + // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
47.442 + if (after) {
47.443 + setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
47.444 + } else {
47.445 + setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
47.446 + }
47.447 + }
47.448 +
47.449 + /**
47.450 + * Sets the daylight saving time end rule. For example, if daylight saving time
47.451 + * ends on the last Sunday in October at 2 am in wall clock time,
47.452 + * you can set the end rule by calling:
47.453 + * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
47.454 + *
47.455 + * @param endMonth The daylight saving time ending month. Month is
47.456 + * a {@link Calendar#MONTH MONTH} field
47.457 + * value (0-based. e.g., 9 for October).
47.458 + * @param endDay The day of the month on which the daylight saving time ends.
47.459 + * See the class description for the special cases of this parameter.
47.460 + * @param endDayOfWeek The daylight saving time ending day-of-week.
47.461 + * See the class description for the special cases of this parameter.
47.462 + * @param endTime The daylight saving ending time in local wall clock time,
47.463 + * (in milliseconds within the day) which is local daylight
47.464 + * time in this case.
47.465 + * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
47.466 + * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
47.467 + */
47.468 + public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
47.469 + int endTime)
47.470 + {
47.471 + this.endMonth = endMonth;
47.472 + this.endDay = endDay;
47.473 + this.endDayOfWeek = endDayOfWeek;
47.474 + this.endTime = endTime;
47.475 + this.endTimeMode = WALL_TIME;
47.476 + decodeEndRule();
47.477 + invalidateCache();
47.478 + }
47.479 +
47.480 + /**
47.481 + * Sets the daylight saving time end rule to a fixed date within a month.
47.482 + * This method is equivalent to:
47.483 + * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
47.484 + *
47.485 + * @param endMonth The daylight saving time ending month. Month is
47.486 + * a {@link Calendar#MONTH MONTH} field
47.487 + * value (0-based. e.g., 9 for October).
47.488 + * @param endDay The day of the month on which the daylight saving time ends.
47.489 + * @param endTime The daylight saving ending time in local wall clock time,
47.490 + * (in milliseconds within the day) which is local daylight
47.491 + * time in this case.
47.492 + * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
47.493 + * or <code>endTime</code> parameters are out of range
47.494 + * @since 1.2
47.495 + */
47.496 + public void setEndRule(int endMonth, int endDay, int endTime)
47.497 + {
47.498 + setEndRule(endMonth, endDay, 0, endTime);
47.499 + }
47.500 +
47.501 + /**
47.502 + * Sets the daylight saving time end rule to a weekday before or after the given date within
47.503 + * a month, e.g., the first Monday on or after the 8th.
47.504 + *
47.505 + * @param endMonth The daylight saving time ending month. Month is
47.506 + * a {@link Calendar#MONTH MONTH} field
47.507 + * value (0-based. e.g., 9 for October).
47.508 + * @param endDay The day of the month on which the daylight saving time ends.
47.509 + * @param endDayOfWeek The daylight saving time ending day-of-week.
47.510 + * @param endTime The daylight saving ending time in local wall clock time,
47.511 + * (in milliseconds within the day) which is local daylight
47.512 + * time in this case.
47.513 + * @param after If true, this rule selects the first <code>endDayOfWeek</code> on
47.514 + * or <em>after</em> <code>endDay</code>. If false, this rule
47.515 + * selects the last <code>endDayOfWeek</code> on or before
47.516 + * <code>endDay</code> of the month.
47.517 + * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
47.518 + * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
47.519 + * @since 1.2
47.520 + */
47.521 + public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
47.522 + {
47.523 + if (after) {
47.524 + setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
47.525 + } else {
47.526 + setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
47.527 + }
47.528 + }
47.529 +
47.530 + /**
47.531 + * Returns the offset of this time zone from UTC at the given
47.532 + * time. If daylight saving time is in effect at the given time,
47.533 + * the offset value is adjusted with the amount of daylight
47.534 + * saving.
47.535 + *
47.536 + * @param date the time at which the time zone offset is found
47.537 + * @return the amount of time in milliseconds to add to UTC to get
47.538 + * local time.
47.539 + * @since 1.4
47.540 + */
47.541 + public int getOffset(long date) {
47.542 + return getOffsets(date, null);
47.543 + }
47.544 +
47.545 + /**
47.546 + * @see TimeZone#getOffsets
47.547 + */
47.548 + int getOffsets(long date, int[] offsets) {
47.549 + int offset = rawOffset;
47.550 +
47.551 + computeOffset:
47.552 + if (useDaylight) {
47.553 + synchronized (this) {
47.554 + if (cacheStart != 0) {
47.555 + if (date >= cacheStart && date < cacheEnd) {
47.556 + offset += dstSavings;
47.557 + break computeOffset;
47.558 + }
47.559 + }
47.560 + }
47.561 + BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
47.562 + gcal : (BaseCalendar) CalendarSystem.forName("julian");
47.563 + BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
47.564 + // Get the year in local time
47.565 + cal.getCalendarDate(date + rawOffset, cdate);
47.566 + int year = cdate.getNormalizedYear();
47.567 + if (year >= startYear) {
47.568 + // Clear time elements for the transition calculations
47.569 + cdate.setTimeOfDay(0, 0, 0, 0);
47.570 + offset = getOffset(cal, cdate, year, date);
47.571 + }
47.572 + }
47.573 +
47.574 + if (offsets != null) {
47.575 + offsets[0] = rawOffset;
47.576 + offsets[1] = offset - rawOffset;
47.577 + }
47.578 + return offset;
47.579 + }
47.580 +
47.581 + /**
47.582 + * Returns the difference in milliseconds between local time and
47.583 + * UTC, taking into account both the raw offset and the effect of
47.584 + * daylight saving, for the specified date and time. This method
47.585 + * assumes that the start and end month are distinct. It also
47.586 + * uses a default {@link GregorianCalendar} object as its
47.587 + * underlying calendar, such as for determining leap years. Do
47.588 + * not use the result of this method with a calendar other than a
47.589 + * default <code>GregorianCalendar</code>.
47.590 + *
47.591 + * <p><em>Note: In general, clients should use
47.592 + * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
47.593 + * instead of calling this method.</em>
47.594 + *
47.595 + * @param era The era of the given date.
47.596 + * @param year The year in the given date.
47.597 + * @param month The month in the given date. Month is 0-based. e.g.,
47.598 + * 0 for January.
47.599 + * @param day The day-in-month of the given date.
47.600 + * @param dayOfWeek The day-of-week of the given date.
47.601 + * @param millis The milliseconds in day in <em>standard</em> local time.
47.602 + * @return The milliseconds to add to UTC to get local time.
47.603 + * @exception IllegalArgumentException the <code>era</code>,
47.604 + * <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
47.605 + * or <code>millis</code> parameters are out of range
47.606 + */
47.607 + public int getOffset(int era, int year, int month, int day, int dayOfWeek,
47.608 + int millis)
47.609 + {
47.610 + if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
47.611 + throw new IllegalArgumentException("Illegal era " + era);
47.612 + }
47.613 +
47.614 + int y = year;
47.615 + if (era == GregorianCalendar.BC) {
47.616 + // adjust y with the GregorianCalendar-style year numbering.
47.617 + y = 1 - y;
47.618 + }
47.619 +
47.620 + // If the year isn't representable with the 64-bit long
47.621 + // integer in milliseconds, convert the year to an
47.622 + // equivalent year. This is required to pass some JCK test cases
47.623 + // which are actually useless though because the specified years
47.624 + // can't be supported by the Java time system.
47.625 + if (y >= 292278994) {
47.626 + y = 2800 + y % 2800;
47.627 + } else if (y <= -292269054) {
47.628 + // y %= 28 also produces an equivalent year, but positive
47.629 + // year numbers would be convenient to use the UNIX cal
47.630 + // command.
47.631 + y = (int) CalendarUtils.mod((long) y, 28);
47.632 + }
47.633 +
47.634 + // convert year to its 1-based month value
47.635 + int m = month + 1;
47.636 +
47.637 + // First, calculate time as a Gregorian date.
47.638 + BaseCalendar cal = gcal;
47.639 + BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
47.640 + cdate.setDate(y, m, day);
47.641 + long time = cal.getTime(cdate); // normalize cdate
47.642 + time += millis - rawOffset; // UTC time
47.643 +
47.644 + // If the time value represents a time before the default
47.645 + // Gregorian cutover, recalculate time using the Julian
47.646 + // calendar system. For the Julian calendar system, the
47.647 + // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
47.648 + // 1, 2 ... which is different from the GregorianCalendar
47.649 + // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
47.650 + if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
47.651 + cal = (BaseCalendar) CalendarSystem.forName("julian");
47.652 + cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
47.653 + cdate.setNormalizedDate(y, m, day);
47.654 + time = cal.getTime(cdate) + millis - rawOffset;
47.655 + }
47.656 +
47.657 + if ((cdate.getNormalizedYear() != y)
47.658 + || (cdate.getMonth() != m)
47.659 + || (cdate.getDayOfMonth() != day)
47.660 + // The validation should be cdate.getDayOfWeek() ==
47.661 + // dayOfWeek. However, we don't check dayOfWeek for
47.662 + // compatibility.
47.663 + || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
47.664 + || (millis < 0 || millis >= (24*60*60*1000))) {
47.665 + throw new IllegalArgumentException();
47.666 + }
47.667 +
47.668 + if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
47.669 + return rawOffset;
47.670 + }
47.671 +
47.672 + return getOffset(cal, cdate, y, time);
47.673 + }
47.674 +
47.675 + private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
47.676 + synchronized (this) {
47.677 + if (cacheStart != 0) {
47.678 + if (time >= cacheStart && time < cacheEnd) {
47.679 + return rawOffset + dstSavings;
47.680 + }
47.681 + if (year == cacheYear) {
47.682 + return rawOffset;
47.683 + }
47.684 + }
47.685 + }
47.686 +
47.687 + long start = getStart(cal, cdate, year);
47.688 + long end = getEnd(cal, cdate, year);
47.689 + int offset = rawOffset;
47.690 + if (start <= end) {
47.691 + if (time >= start && time < end) {
47.692 + offset += dstSavings;
47.693 + }
47.694 + synchronized (this) {
47.695 + cacheYear = year;
47.696 + cacheStart = start;
47.697 + cacheEnd = end;
47.698 + }
47.699 + } else {
47.700 + if (time < end) {
47.701 + // TODO: support Gregorian cutover. The previous year
47.702 + // may be in the other calendar system.
47.703 + start = getStart(cal, cdate, year - 1);
47.704 + if (time >= start) {
47.705 + offset += dstSavings;
47.706 + }
47.707 + } else if (time >= start) {
47.708 + // TODO: support Gregorian cutover. The next year
47.709 + // may be in the other calendar system.
47.710 + end = getEnd(cal, cdate, year + 1);
47.711 + if (time < end) {
47.712 + offset += dstSavings;
47.713 + }
47.714 + }
47.715 + if (start <= end) {
47.716 + synchronized (this) {
47.717 + // The start and end transitions are in multiple years.
47.718 + cacheYear = (long) startYear - 1;
47.719 + cacheStart = start;
47.720 + cacheEnd = end;
47.721 + }
47.722 + }
47.723 + }
47.724 + return offset;
47.725 + }
47.726 +
47.727 + private long getStart(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
47.728 + int time = startTime;
47.729 + if (startTimeMode != UTC_TIME) {
47.730 + time -= rawOffset;
47.731 + }
47.732 + return getTransition(cal, cdate, startMode, year, startMonth, startDay,
47.733 + startDayOfWeek, time);
47.734 + }
47.735 +
47.736 + private long getEnd(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
47.737 + int time = endTime;
47.738 + if (endTimeMode != UTC_TIME) {
47.739 + time -= rawOffset;
47.740 + }
47.741 + if (endTimeMode == WALL_TIME) {
47.742 + time -= dstSavings;
47.743 + }
47.744 + return getTransition(cal, cdate, endMode, year, endMonth, endDay,
47.745 + endDayOfWeek, time);
47.746 + }
47.747 +
47.748 + private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate,
47.749 + int mode, int year, int month, int dayOfMonth,
47.750 + int dayOfWeek, int timeOfDay) {
47.751 + cdate.setNormalizedYear(year);
47.752 + cdate.setMonth(month + 1);
47.753 + switch (mode) {
47.754 + case DOM_MODE:
47.755 + cdate.setDayOfMonth(dayOfMonth);
47.756 + break;
47.757 +
47.758 + case DOW_IN_MONTH_MODE:
47.759 + cdate.setDayOfMonth(1);
47.760 + if (dayOfMonth < 0) {
47.761 + cdate.setDayOfMonth(cal.getMonthLength(cdate));
47.762 + }
47.763 + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
47.764 + break;
47.765 +
47.766 + case DOW_GE_DOM_MODE:
47.767 + cdate.setDayOfMonth(dayOfMonth);
47.768 + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
47.769 + break;
47.770 +
47.771 + case DOW_LE_DOM_MODE:
47.772 + cdate.setDayOfMonth(dayOfMonth);
47.773 + cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
47.774 + break;
47.775 + }
47.776 + return cal.getTime(cdate) + timeOfDay;
47.777 + }
47.778 +
47.779 + /**
47.780 + * Gets the GMT offset for this time zone.
47.781 + * @return the GMT offset value in milliseconds
47.782 + * @see #setRawOffset
47.783 + */
47.784 + public int getRawOffset()
47.785 + {
47.786 + // The given date will be taken into account while
47.787 + // we have the historical time zone data in place.
47.788 + return rawOffset;
47.789 + }
47.790 +
47.791 + /**
47.792 + * Sets the base time zone offset to GMT.
47.793 + * This is the offset to add to UTC to get local time.
47.794 + * @see #getRawOffset
47.795 + */
47.796 + public void setRawOffset(int offsetMillis)
47.797 + {
47.798 + this.rawOffset = offsetMillis;
47.799 + }
47.800 +
47.801 + /**
47.802 + * Sets the amount of time in milliseconds that the clock is advanced
47.803 + * during daylight saving time.
47.804 + * @param millisSavedDuringDST the number of milliseconds the time is
47.805 + * advanced with respect to standard time when the daylight saving time rules
47.806 + * are in effect. A positive number, typically one hour (3600000).
47.807 + * @see #getDSTSavings
47.808 + * @since 1.2
47.809 + */
47.810 + public void setDSTSavings(int millisSavedDuringDST) {
47.811 + if (millisSavedDuringDST <= 0) {
47.812 + throw new IllegalArgumentException("Illegal daylight saving value: "
47.813 + + millisSavedDuringDST);
47.814 + }
47.815 + dstSavings = millisSavedDuringDST;
47.816 + }
47.817 +
47.818 + /**
47.819 + * Returns the amount of time in milliseconds that the clock is
47.820 + * advanced during daylight saving time.
47.821 + *
47.822 + * @return the number of milliseconds the time is advanced with
47.823 + * respect to standard time when the daylight saving rules are in
47.824 + * effect, or 0 (zero) if this time zone doesn't observe daylight
47.825 + * saving time.
47.826 + *
47.827 + * @see #setDSTSavings
47.828 + * @since 1.2
47.829 + */
47.830 + public int getDSTSavings() {
47.831 + return useDaylight ? dstSavings : 0;
47.832 + }
47.833 +
47.834 + /**
47.835 + * Queries if this time zone uses daylight saving time.
47.836 + * @return true if this time zone uses daylight saving time;
47.837 + * false otherwise.
47.838 + */
47.839 + public boolean useDaylightTime()
47.840 + {
47.841 + return useDaylight;
47.842 + }
47.843 +
47.844 + /**
47.845 + * Returns {@code true} if this {@code SimpleTimeZone} observes
47.846 + * Daylight Saving Time. This method is equivalent to {@link
47.847 + * #useDaylightTime()}.
47.848 + *
47.849 + * @return {@code true} if this {@code SimpleTimeZone} observes
47.850 + * Daylight Saving Time; {@code false} otherwise.
47.851 + * @since 1.7
47.852 + */
47.853 + @Override
47.854 + public boolean observesDaylightTime() {
47.855 + return useDaylightTime();
47.856 + }
47.857 +
47.858 + /**
47.859 + * Queries if the given date is in daylight saving time.
47.860 + * @return true if daylight saving time is in effective at the
47.861 + * given date; false otherwise.
47.862 + */
47.863 + public boolean inDaylightTime(Date date)
47.864 + {
47.865 + return (getOffset(date.getTime()) != rawOffset);
47.866 + }
47.867 +
47.868 + /**
47.869 + * Returns a clone of this <code>SimpleTimeZone</code> instance.
47.870 + * @return a clone of this instance.
47.871 + */
47.872 + public Object clone()
47.873 + {
47.874 + return super.clone();
47.875 + }
47.876 +
47.877 + /**
47.878 + * Generates the hash code for the SimpleDateFormat object.
47.879 + * @return the hash code for this object
47.880 + */
47.881 + public synchronized int hashCode()
47.882 + {
47.883 + return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
47.884 + endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
47.885 + }
47.886 +
47.887 + /**
47.888 + * Compares the equality of two <code>SimpleTimeZone</code> objects.
47.889 + *
47.890 + * @param obj The <code>SimpleTimeZone</code> object to be compared with.
47.891 + * @return True if the given <code>obj</code> is the same as this
47.892 + * <code>SimpleTimeZone</code> object; false otherwise.
47.893 + */
47.894 + public boolean equals(Object obj)
47.895 + {
47.896 + if (this == obj) {
47.897 + return true;
47.898 + }
47.899 + if (!(obj instanceof SimpleTimeZone)) {
47.900 + return false;
47.901 + }
47.902 +
47.903 + SimpleTimeZone that = (SimpleTimeZone) obj;
47.904 +
47.905 + return getID().equals(that.getID()) &&
47.906 + hasSameRules(that);
47.907 + }
47.908 +
47.909 + /**
47.910 + * Returns <code>true</code> if this zone has the same rules and offset as another zone.
47.911 + * @param other the TimeZone object to be compared with
47.912 + * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
47.913 + * same rules and offset as this one
47.914 + * @since 1.2
47.915 + */
47.916 + public boolean hasSameRules(TimeZone other) {
47.917 + if (this == other) {
47.918 + return true;
47.919 + }
47.920 + if (!(other instanceof SimpleTimeZone)) {
47.921 + return false;
47.922 + }
47.923 + SimpleTimeZone that = (SimpleTimeZone) other;
47.924 + return rawOffset == that.rawOffset &&
47.925 + useDaylight == that.useDaylight &&
47.926 + (!useDaylight
47.927 + // Only check rules if using DST
47.928 + || (dstSavings == that.dstSavings &&
47.929 + startMode == that.startMode &&
47.930 + startMonth == that.startMonth &&
47.931 + startDay == that.startDay &&
47.932 + startDayOfWeek == that.startDayOfWeek &&
47.933 + startTime == that.startTime &&
47.934 + startTimeMode == that.startTimeMode &&
47.935 + endMode == that.endMode &&
47.936 + endMonth == that.endMonth &&
47.937 + endDay == that.endDay &&
47.938 + endDayOfWeek == that.endDayOfWeek &&
47.939 + endTime == that.endTime &&
47.940 + endTimeMode == that.endTimeMode &&
47.941 + startYear == that.startYear));
47.942 + }
47.943 +
47.944 + /**
47.945 + * Returns a string representation of this time zone.
47.946 + * @return a string representation of this time zone.
47.947 + */
47.948 + public String toString() {
47.949 + return getClass().getName() +
47.950 + "[id=" + getID() +
47.951 + ",offset=" + rawOffset +
47.952 + ",dstSavings=" + dstSavings +
47.953 + ",useDaylight=" + useDaylight +
47.954 + ",startYear=" + startYear +
47.955 + ",startMode=" + startMode +
47.956 + ",startMonth=" + startMonth +
47.957 + ",startDay=" + startDay +
47.958 + ",startDayOfWeek=" + startDayOfWeek +
47.959 + ",startTime=" + startTime +
47.960 + ",startTimeMode=" + startTimeMode +
47.961 + ",endMode=" + endMode +
47.962 + ",endMonth=" + endMonth +
47.963 + ",endDay=" + endDay +
47.964 + ",endDayOfWeek=" + endDayOfWeek +
47.965 + ",endTime=" + endTime +
47.966 + ",endTimeMode=" + endTimeMode + ']';
47.967 + }
47.968 +
47.969 + // =======================privates===============================
47.970 +
47.971 + /**
47.972 + * The month in which daylight saving time starts. This value must be
47.973 + * between <code>Calendar.JANUARY</code> and
47.974 + * <code>Calendar.DECEMBER</code> inclusive. This value must not equal
47.975 + * <code>endMonth</code>.
47.976 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.977 + * @serial
47.978 + */
47.979 + private int startMonth;
47.980 +
47.981 + /**
47.982 + * This field has two possible interpretations:
47.983 + * <dl>
47.984 + * <dt><code>startMode == DOW_IN_MONTH</code></dt>
47.985 + * <dd>
47.986 + * <code>startDay</code> indicates the day of the month of
47.987 + * <code>startMonth</code> on which daylight
47.988 + * saving time starts, from 1 to 28, 30, or 31, depending on the
47.989 + * <code>startMonth</code>.
47.990 + * </dd>
47.991 + * <dt><code>startMode != DOW_IN_MONTH</code></dt>
47.992 + * <dd>
47.993 + * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
47.994 + * month <code>startMonth</code> daylight
47.995 + * saving time starts on. For example, a value of +1 and a
47.996 + * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
47.997 + * first Sunday of <code>startMonth</code>. Likewise, +2 would indicate the
47.998 + * second Sunday, and -1 the last Sunday. A value of 0 is illegal.
47.999 + * </dd>
47.1000 + * </dl>
47.1001 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1002 + * @serial
47.1003 + */
47.1004 + private int startDay;
47.1005 +
47.1006 + /**
47.1007 + * The day of the week on which daylight saving time starts. This value
47.1008 + * must be between <code>Calendar.SUNDAY</code> and
47.1009 + * <code>Calendar.SATURDAY</code> inclusive.
47.1010 + * <p>If <code>useDaylight</code> is false or
47.1011 + * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
47.1012 + * @serial
47.1013 + */
47.1014 + private int startDayOfWeek;
47.1015 +
47.1016 + /**
47.1017 + * The time in milliseconds after midnight at which daylight saving
47.1018 + * time starts. This value is expressed as wall time, standard time,
47.1019 + * or UTC time, depending on the setting of <code>startTimeMode</code>.
47.1020 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1021 + * @serial
47.1022 + */
47.1023 + private int startTime;
47.1024 +
47.1025 + /**
47.1026 + * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
47.1027 + * @serial
47.1028 + * @since 1.3
47.1029 + */
47.1030 + private int startTimeMode;
47.1031 +
47.1032 + /**
47.1033 + * The month in which daylight saving time ends. This value must be
47.1034 + * between <code>Calendar.JANUARY</code> and
47.1035 + * <code>Calendar.UNDECIMBER</code>. This value must not equal
47.1036 + * <code>startMonth</code>.
47.1037 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1038 + * @serial
47.1039 + */
47.1040 + private int endMonth;
47.1041 +
47.1042 + /**
47.1043 + * This field has two possible interpretations:
47.1044 + * <dl>
47.1045 + * <dt><code>endMode == DOW_IN_MONTH</code></dt>
47.1046 + * <dd>
47.1047 + * <code>endDay</code> indicates the day of the month of
47.1048 + * <code>endMonth</code> on which daylight
47.1049 + * saving time ends, from 1 to 28, 30, or 31, depending on the
47.1050 + * <code>endMonth</code>.
47.1051 + * </dd>
47.1052 + * <dt><code>endMode != DOW_IN_MONTH</code></dt>
47.1053 + * <dd>
47.1054 + * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
47.1055 + * month <code>endMonth</code> daylight
47.1056 + * saving time ends on. For example, a value of +1 and a
47.1057 + * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
47.1058 + * first Sunday of <code>endMonth</code>. Likewise, +2 would indicate the
47.1059 + * second Sunday, and -1 the last Sunday. A value of 0 is illegal.
47.1060 + * </dd>
47.1061 + * </dl>
47.1062 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1063 + * @serial
47.1064 + */
47.1065 + private int endDay;
47.1066 +
47.1067 + /**
47.1068 + * The day of the week on which daylight saving time ends. This value
47.1069 + * must be between <code>Calendar.SUNDAY</code> and
47.1070 + * <code>Calendar.SATURDAY</code> inclusive.
47.1071 + * <p>If <code>useDaylight</code> is false or
47.1072 + * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
47.1073 + * @serial
47.1074 + */
47.1075 + private int endDayOfWeek;
47.1076 +
47.1077 + /**
47.1078 + * The time in milliseconds after midnight at which daylight saving
47.1079 + * time ends. This value is expressed as wall time, standard time,
47.1080 + * or UTC time, depending on the setting of <code>endTimeMode</code>.
47.1081 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1082 + * @serial
47.1083 + */
47.1084 + private int endTime;
47.1085 +
47.1086 + /**
47.1087 + * The format of endTime, either <code>WALL_TIME</code>,
47.1088 + * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
47.1089 + * @serial
47.1090 + * @since 1.3
47.1091 + */
47.1092 + private int endTimeMode;
47.1093 +
47.1094 + /**
47.1095 + * The year in which daylight saving time is first observed. This is an {@link GregorianCalendar#AD AD}
47.1096 + * value. If this value is less than 1 then daylight saving time is observed
47.1097 + * for all <code>AD</code> years.
47.1098 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1099 + * @serial
47.1100 + */
47.1101 + private int startYear;
47.1102 +
47.1103 + /**
47.1104 + * The offset in milliseconds between this zone and GMT. Negative offsets
47.1105 + * are to the west of Greenwich. To obtain local <em>standard</em> time,
47.1106 + * add the offset to GMT time. To obtain local wall time it may also be
47.1107 + * necessary to add <code>dstSavings</code>.
47.1108 + * @serial
47.1109 + */
47.1110 + private int rawOffset;
47.1111 +
47.1112 + /**
47.1113 + * A boolean value which is true if and only if this zone uses daylight
47.1114 + * saving time. If this value is false, several other fields are ignored.
47.1115 + * @serial
47.1116 + */
47.1117 + private boolean useDaylight=false; // indicate if this time zone uses DST
47.1118 +
47.1119 + private static final int millisPerHour = 60*60*1000;
47.1120 + private static final int millisPerDay = 24*millisPerHour;
47.1121 +
47.1122 + /**
47.1123 + * This field was serialized in JDK 1.1, so we have to keep it that way
47.1124 + * to maintain serialization compatibility. However, there's no need to
47.1125 + * recreate the array each time we create a new time zone.
47.1126 + * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
47.1127 + * 31, 31, 30, 31, 30, 31}. This is ignored as of the Java 2 platform v1.2, however, it must
47.1128 + * be streamed out for compatibility with JDK 1.1.
47.1129 + */
47.1130 + private final byte monthLength[] = staticMonthLength;
47.1131 + private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
47.1132 + private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
47.1133 +
47.1134 + /**
47.1135 + * Variables specifying the mode of the start rule. Takes the following
47.1136 + * values:
47.1137 + * <dl>
47.1138 + * <dt><code>DOM_MODE</code></dt>
47.1139 + * <dd>
47.1140 + * Exact day of week; e.g., March 1.
47.1141 + * </dd>
47.1142 + * <dt><code>DOW_IN_MONTH_MODE</code></dt>
47.1143 + * <dd>
47.1144 + * Day of week in month; e.g., last Sunday in March.
47.1145 + * </dd>
47.1146 + * <dt><code>DOW_GE_DOM_MODE</code></dt>
47.1147 + * <dd>
47.1148 + * Day of week after day of month; e.g., Sunday on or after March 15.
47.1149 + * </dd>
47.1150 + * <dt><code>DOW_LE_DOM_MODE</code></dt>
47.1151 + * <dd>
47.1152 + * Day of week before day of month; e.g., Sunday on or before March 15.
47.1153 + * </dd>
47.1154 + * </dl>
47.1155 + * The setting of this field affects the interpretation of the
47.1156 + * <code>startDay</code> field.
47.1157 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1158 + * @serial
47.1159 + * @since 1.1.4
47.1160 + */
47.1161 + private int startMode;
47.1162 +
47.1163 + /**
47.1164 + * Variables specifying the mode of the end rule. Takes the following
47.1165 + * values:
47.1166 + * <dl>
47.1167 + * <dt><code>DOM_MODE</code></dt>
47.1168 + * <dd>
47.1169 + * Exact day of week; e.g., March 1.
47.1170 + * </dd>
47.1171 + * <dt><code>DOW_IN_MONTH_MODE</code></dt>
47.1172 + * <dd>
47.1173 + * Day of week in month; e.g., last Sunday in March.
47.1174 + * </dd>
47.1175 + * <dt><code>DOW_GE_DOM_MODE</code></dt>
47.1176 + * <dd>
47.1177 + * Day of week after day of month; e.g., Sunday on or after March 15.
47.1178 + * </dd>
47.1179 + * <dt><code>DOW_LE_DOM_MODE</code></dt>
47.1180 + * <dd>
47.1181 + * Day of week before day of month; e.g., Sunday on or before March 15.
47.1182 + * </dd>
47.1183 + * </dl>
47.1184 + * The setting of this field affects the interpretation of the
47.1185 + * <code>endDay</code> field.
47.1186 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1187 + * @serial
47.1188 + * @since 1.1.4
47.1189 + */
47.1190 + private int endMode;
47.1191 +
47.1192 + /**
47.1193 + * A positive value indicating the amount of time saved during DST in
47.1194 + * milliseconds.
47.1195 + * Typically one hour (3600000); sometimes 30 minutes (1800000).
47.1196 + * <p>If <code>useDaylight</code> is false, this value is ignored.
47.1197 + * @serial
47.1198 + * @since 1.1.4
47.1199 + */
47.1200 + private int dstSavings;
47.1201 +
47.1202 + private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
47.1203 +
47.1204 + /**
47.1205 + * Cache values representing a single period of daylight saving
47.1206 + * time. When the cache values are valid, cacheStart is the start
47.1207 + * time (inclusive) of daylight saving time and cacheEnd is the
47.1208 + * end time (exclusive).
47.1209 + *
47.1210 + * cacheYear has a year value if both cacheStart and cacheEnd are
47.1211 + * in the same year. cacheYear is set to startYear - 1 if
47.1212 + * cacheStart and cacheEnd are in different years. cacheStart is 0
47.1213 + * if the cache values are void. cacheYear is a long to support
47.1214 + * Integer.MIN_VALUE - 1 (JCK requirement).
47.1215 + */
47.1216 + private transient long cacheYear;
47.1217 + private transient long cacheStart;
47.1218 + private transient long cacheEnd;
47.1219 +
47.1220 + /**
47.1221 + * Constants specifying values of startMode and endMode.
47.1222 + */
47.1223 + private static final int DOM_MODE = 1; // Exact day of month, "Mar 1"
47.1224 + private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
47.1225 + private static final int DOW_GE_DOM_MODE = 3; // Day of week after day of month, "Sun>=15"
47.1226 + private static final int DOW_LE_DOM_MODE = 4; // Day of week before day of month, "Sun<=21"
47.1227 +
47.1228 + /**
47.1229 + * Constant for a mode of start or end time specified as wall clock
47.1230 + * time. Wall clock time is standard time for the onset rule, and
47.1231 + * daylight time for the end rule.
47.1232 + * @since 1.4
47.1233 + */
47.1234 + public static final int WALL_TIME = 0; // Zero for backward compatibility
47.1235 +
47.1236 + /**
47.1237 + * Constant for a mode of start or end time specified as standard time.
47.1238 + * @since 1.4
47.1239 + */
47.1240 + public static final int STANDARD_TIME = 1;
47.1241 +
47.1242 + /**
47.1243 + * Constant for a mode of start or end time specified as UTC. European
47.1244 + * Union rules are specified as UTC time, for example.
47.1245 + * @since 1.4
47.1246 + */
47.1247 + public static final int UTC_TIME = 2;
47.1248 +
47.1249 + // Proclaim compatibility with 1.1
47.1250 + static final long serialVersionUID = -403250971215465050L;
47.1251 +
47.1252 + // the internal serial version which says which version was written
47.1253 + // - 0 (default) for version up to JDK 1.1.3
47.1254 + // - 1 for version from JDK 1.1.4, which includes 3 new fields
47.1255 + // - 2 for JDK 1.3, which includes 2 new fields
47.1256 + static final int currentSerialVersion = 2;
47.1257 +
47.1258 + /**
47.1259 + * The version of the serialized data on the stream. Possible values:
47.1260 + * <dl>
47.1261 + * <dt><b>0</b> or not present on stream</dt>
47.1262 + * <dd>
47.1263 + * JDK 1.1.3 or earlier.
47.1264 + * </dd>
47.1265 + * <dt><b>1</b></dt>
47.1266 + * <dd>
47.1267 + * JDK 1.1.4 or later. Includes three new fields: <code>startMode</code>,
47.1268 + * <code>endMode</code>, and <code>dstSavings</code>.
47.1269 + * </dd>
47.1270 + * <dt><b>2</b></dt>
47.1271 + * <dd>
47.1272 + * JDK 1.3 or later. Includes two new fields: <code>startTimeMode</code>
47.1273 + * and <code>endTimeMode</code>.
47.1274 + * </dd>
47.1275 + * </dl>
47.1276 + * When streaming out this class, the most recent format
47.1277 + * and the highest allowable <code>serialVersionOnStream</code>
47.1278 + * is written.
47.1279 + * @serial
47.1280 + * @since 1.1.4
47.1281 + */
47.1282 + private int serialVersionOnStream = currentSerialVersion;
47.1283 +
47.1284 + synchronized private void invalidateCache() {
47.1285 + cacheYear = startYear - 1;
47.1286 + cacheStart = cacheEnd = 0;
47.1287 + }
47.1288 +
47.1289 + //----------------------------------------------------------------------
47.1290 + // Rule representation
47.1291 + //
47.1292 + // We represent the following flavors of rules:
47.1293 + // 5 the fifth of the month
47.1294 + // lastSun the last Sunday in the month
47.1295 + // lastMon the last Monday in the month
47.1296 + // Sun>=8 first Sunday on or after the eighth
47.1297 + // Sun<=25 last Sunday on or before the 25th
47.1298 + // This is further complicated by the fact that we need to remain
47.1299 + // backward compatible with the 1.1 FCS. Finally, we need to minimize
47.1300 + // API changes. In order to satisfy these requirements, we support
47.1301 + // three representation systems, and we translate between them.
47.1302 + //
47.1303 + // INTERNAL REPRESENTATION
47.1304 + // This is the format SimpleTimeZone objects take after construction or
47.1305 + // streaming in is complete. Rules are represented directly, using an
47.1306 + // unencoded format. We will discuss the start rule only below; the end
47.1307 + // rule is analogous.
47.1308 + // startMode Takes on enumerated values DAY_OF_MONTH,
47.1309 + // DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
47.1310 + // startDay The day of the month, or for DOW_IN_MONTH mode, a
47.1311 + // value indicating which DOW, such as +1 for first,
47.1312 + // +2 for second, -1 for last, etc.
47.1313 + // startDayOfWeek The day of the week. Ignored for DAY_OF_MONTH.
47.1314 + //
47.1315 + // ENCODED REPRESENTATION
47.1316 + // This is the format accepted by the constructor and by setStartRule()
47.1317 + // and setEndRule(). It uses various combinations of positive, negative,
47.1318 + // and zero values to encode the different rules. This representation
47.1319 + // allows us to specify all the different rule flavors without altering
47.1320 + // the API.
47.1321 + // MODE startMonth startDay startDayOfWeek
47.1322 + // DOW_IN_MONTH_MODE >=0 !=0 >0
47.1323 + // DOM_MODE >=0 >0 ==0
47.1324 + // DOW_GE_DOM_MODE >=0 >0 <0
47.1325 + // DOW_LE_DOM_MODE >=0 <0 <0
47.1326 + // (no DST) don't care ==0 don't care
47.1327 + //
47.1328 + // STREAMED REPRESENTATION
47.1329 + // We must retain binary compatibility with the 1.1 FCS. The 1.1 code only
47.1330 + // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
47.1331 + // flag useDaylight. When we stream an object out, we translate into an
47.1332 + // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
47.1333 + // and used by 1.1 code. Following that, we write out the full
47.1334 + // representation separately so that contemporary code can recognize and
47.1335 + // parse it. The full representation is written in a "packed" format,
47.1336 + // consisting of a version number, a length, and an array of bytes. Future
47.1337 + // versions of this class may specify different versions. If they wish to
47.1338 + // include additional data, they should do so by storing them after the
47.1339 + // packed representation below.
47.1340 + //----------------------------------------------------------------------
47.1341 +
47.1342 + /**
47.1343 + * Given a set of encoded rules in startDay and startDayOfMonth, decode
47.1344 + * them and set the startMode appropriately. Do the same for endDay and
47.1345 + * endDayOfMonth. Upon entry, the day of week variables may be zero or
47.1346 + * negative, in order to indicate special modes. The day of month
47.1347 + * variables may also be negative. Upon exit, the mode variables will be
47.1348 + * set, and the day of week and day of month variables will be positive.
47.1349 + * This method also recognizes a startDay or endDay of zero as indicating
47.1350 + * no DST.
47.1351 + */
47.1352 + private void decodeRules()
47.1353 + {
47.1354 + decodeStartRule();
47.1355 + decodeEndRule();
47.1356 + }
47.1357 +
47.1358 + /**
47.1359 + * Decode the start rule and validate the parameters. The parameters are
47.1360 + * expected to be in encoded form, which represents the various rule modes
47.1361 + * by negating or zeroing certain values. Representation formats are:
47.1362 + * <p>
47.1363 + * <pre>
47.1364 + * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST
47.1365 + * ------------ ----- -------- -------- ----------
47.1366 + * month 0..11 same same same don't care
47.1367 + * day -5..5 1..31 1..31 -1..-31 0
47.1368 + * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care
47.1369 + * time 0..ONEDAY same same same don't care
47.1370 + * </pre>
47.1371 + * The range for month does not include UNDECIMBER since this class is
47.1372 + * really specific to GregorianCalendar, which does not use that month.
47.1373 + * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
47.1374 + * end rule is an exclusive limit point. That is, the range of times that
47.1375 + * are in DST include those >= the start and < the end. For this reason,
47.1376 + * it should be possible to specify an end of ONEDAY in order to include the
47.1377 + * entire day. Although this is equivalent to time 0 of the following day,
47.1378 + * it's not always possible to specify that, for example, on December 31.
47.1379 + * While arguably the start range should still be 0..ONEDAY-1, we keep
47.1380 + * the start and end ranges the same for consistency.
47.1381 + */
47.1382 + private void decodeStartRule() {
47.1383 + useDaylight = (startDay != 0) && (endDay != 0);
47.1384 + if (startDay != 0) {
47.1385 + if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
47.1386 + throw new IllegalArgumentException(
47.1387 + "Illegal start month " + startMonth);
47.1388 + }
47.1389 + if (startTime < 0 || startTime > millisPerDay) {
47.1390 + throw new IllegalArgumentException(
47.1391 + "Illegal start time " + startTime);
47.1392 + }
47.1393 + if (startDayOfWeek == 0) {
47.1394 + startMode = DOM_MODE;
47.1395 + } else {
47.1396 + if (startDayOfWeek > 0) {
47.1397 + startMode = DOW_IN_MONTH_MODE;
47.1398 + } else {
47.1399 + startDayOfWeek = -startDayOfWeek;
47.1400 + if (startDay > 0) {
47.1401 + startMode = DOW_GE_DOM_MODE;
47.1402 + } else {
47.1403 + startDay = -startDay;
47.1404 + startMode = DOW_LE_DOM_MODE;
47.1405 + }
47.1406 + }
47.1407 + if (startDayOfWeek > Calendar.SATURDAY) {
47.1408 + throw new IllegalArgumentException(
47.1409 + "Illegal start day of week " + startDayOfWeek);
47.1410 + }
47.1411 + }
47.1412 + if (startMode == DOW_IN_MONTH_MODE) {
47.1413 + if (startDay < -5 || startDay > 5) {
47.1414 + throw new IllegalArgumentException(
47.1415 + "Illegal start day of week in month " + startDay);
47.1416 + }
47.1417 + } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
47.1418 + throw new IllegalArgumentException(
47.1419 + "Illegal start day " + startDay);
47.1420 + }
47.1421 + }
47.1422 + }
47.1423 +
47.1424 + /**
47.1425 + * Decode the end rule and validate the parameters. This method is exactly
47.1426 + * analogous to decodeStartRule().
47.1427 + * @see decodeStartRule
47.1428 + */
47.1429 + private void decodeEndRule() {
47.1430 + useDaylight = (startDay != 0) && (endDay != 0);
47.1431 + if (endDay != 0) {
47.1432 + if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
47.1433 + throw new IllegalArgumentException(
47.1434 + "Illegal end month " + endMonth);
47.1435 + }
47.1436 + if (endTime < 0 || endTime > millisPerDay) {
47.1437 + throw new IllegalArgumentException(
47.1438 + "Illegal end time " + endTime);
47.1439 + }
47.1440 + if (endDayOfWeek == 0) {
47.1441 + endMode = DOM_MODE;
47.1442 + } else {
47.1443 + if (endDayOfWeek > 0) {
47.1444 + endMode = DOW_IN_MONTH_MODE;
47.1445 + } else {
47.1446 + endDayOfWeek = -endDayOfWeek;
47.1447 + if (endDay > 0) {
47.1448 + endMode = DOW_GE_DOM_MODE;
47.1449 + } else {
47.1450 + endDay = -endDay;
47.1451 + endMode = DOW_LE_DOM_MODE;
47.1452 + }
47.1453 + }
47.1454 + if (endDayOfWeek > Calendar.SATURDAY) {
47.1455 + throw new IllegalArgumentException(
47.1456 + "Illegal end day of week " + endDayOfWeek);
47.1457 + }
47.1458 + }
47.1459 + if (endMode == DOW_IN_MONTH_MODE) {
47.1460 + if (endDay < -5 || endDay > 5) {
47.1461 + throw new IllegalArgumentException(
47.1462 + "Illegal end day of week in month " + endDay);
47.1463 + }
47.1464 + } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
47.1465 + throw new IllegalArgumentException(
47.1466 + "Illegal end day " + endDay);
47.1467 + }
47.1468 + }
47.1469 + }
47.1470 +
47.1471 + /**
47.1472 + * Make rules compatible to 1.1 FCS code. Since 1.1 FCS code only understands
47.1473 + * day-of-week-in-month rules, we must modify other modes of rules to their
47.1474 + * approximate equivalent in 1.1 FCS terms. This method is used when streaming
47.1475 + * out objects of this class. After it is called, the rules will be modified,
47.1476 + * with a possible loss of information. startMode and endMode will NOT be
47.1477 + * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
47.1478 + * since the rule modification is only intended to be temporary.
47.1479 + */
47.1480 + private void makeRulesCompatible()
47.1481 + {
47.1482 + switch (startMode) {
47.1483 + case DOM_MODE:
47.1484 + startDay = 1 + (startDay / 7);
47.1485 + startDayOfWeek = Calendar.SUNDAY;
47.1486 + break;
47.1487 +
47.1488 + case DOW_GE_DOM_MODE:
47.1489 + // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
47.1490 + // that is, Sun>=1 == firstSun.
47.1491 + if (startDay != 1) {
47.1492 + startDay = 1 + (startDay / 7);
47.1493 + }
47.1494 + break;
47.1495 +
47.1496 + case DOW_LE_DOM_MODE:
47.1497 + if (startDay >= 30) {
47.1498 + startDay = -1;
47.1499 + } else {
47.1500 + startDay = 1 + (startDay / 7);
47.1501 + }
47.1502 + break;
47.1503 + }
47.1504 +
47.1505 + switch (endMode) {
47.1506 + case DOM_MODE:
47.1507 + endDay = 1 + (endDay / 7);
47.1508 + endDayOfWeek = Calendar.SUNDAY;
47.1509 + break;
47.1510 +
47.1511 + case DOW_GE_DOM_MODE:
47.1512 + // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
47.1513 + // that is, Sun>=1 == firstSun.
47.1514 + if (endDay != 1) {
47.1515 + endDay = 1 + (endDay / 7);
47.1516 + }
47.1517 + break;
47.1518 +
47.1519 + case DOW_LE_DOM_MODE:
47.1520 + if (endDay >= 30) {
47.1521 + endDay = -1;
47.1522 + } else {
47.1523 + endDay = 1 + (endDay / 7);
47.1524 + }
47.1525 + break;
47.1526 + }
47.1527 +
47.1528 + /*
47.1529 + * Adjust the start and end times to wall time. This works perfectly
47.1530 + * well unless it pushes into the next or previous day. If that
47.1531 + * happens, we attempt to adjust the day rule somewhat crudely. The day
47.1532 + * rules have been forced into DOW_IN_MONTH mode already, so we change
47.1533 + * the day of week to move forward or back by a day. It's possible to
47.1534 + * make a more refined adjustment of the original rules first, but in
47.1535 + * most cases this extra effort will go to waste once we adjust the day
47.1536 + * rules anyway.
47.1537 + */
47.1538 + switch (startTimeMode) {
47.1539 + case UTC_TIME:
47.1540 + startTime += rawOffset;
47.1541 + break;
47.1542 + }
47.1543 + while (startTime < 0) {
47.1544 + startTime += millisPerDay;
47.1545 + startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
47.1546 + }
47.1547 + while (startTime >= millisPerDay) {
47.1548 + startTime -= millisPerDay;
47.1549 + startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
47.1550 + }
47.1551 +
47.1552 + switch (endTimeMode) {
47.1553 + case UTC_TIME:
47.1554 + endTime += rawOffset + dstSavings;
47.1555 + break;
47.1556 + case STANDARD_TIME:
47.1557 + endTime += dstSavings;
47.1558 + }
47.1559 + while (endTime < 0) {
47.1560 + endTime += millisPerDay;
47.1561 + endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
47.1562 + }
47.1563 + while (endTime >= millisPerDay) {
47.1564 + endTime -= millisPerDay;
47.1565 + endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
47.1566 + }
47.1567 + }
47.1568 +
47.1569 + /**
47.1570 + * Pack the start and end rules into an array of bytes. Only pack
47.1571 + * data which is not preserved by makeRulesCompatible.
47.1572 + */
47.1573 + private byte[] packRules()
47.1574 + {
47.1575 + byte[] rules = new byte[6];
47.1576 + rules[0] = (byte)startDay;
47.1577 + rules[1] = (byte)startDayOfWeek;
47.1578 + rules[2] = (byte)endDay;
47.1579 + rules[3] = (byte)endDayOfWeek;
47.1580 +
47.1581 + // As of serial version 2, include time modes
47.1582 + rules[4] = (byte)startTimeMode;
47.1583 + rules[5] = (byte)endTimeMode;
47.1584 +
47.1585 + return rules;
47.1586 + }
47.1587 +
47.1588 + /**
47.1589 + * Given an array of bytes produced by packRules, interpret them
47.1590 + * as the start and end rules.
47.1591 + */
47.1592 + private void unpackRules(byte[] rules)
47.1593 + {
47.1594 + startDay = rules[0];
47.1595 + startDayOfWeek = rules[1];
47.1596 + endDay = rules[2];
47.1597 + endDayOfWeek = rules[3];
47.1598 +
47.1599 + // As of serial version 2, include time modes
47.1600 + if (rules.length >= 6) {
47.1601 + startTimeMode = rules[4];
47.1602 + endTimeMode = rules[5];
47.1603 + }
47.1604 + }
47.1605 +
47.1606 + /**
47.1607 + * Pack the start and end times into an array of bytes. This is required
47.1608 + * as of serial version 2.
47.1609 + */
47.1610 + private int[] packTimes() {
47.1611 + int[] times = new int[2];
47.1612 + times[0] = startTime;
47.1613 + times[1] = endTime;
47.1614 + return times;
47.1615 + }
47.1616 +
47.1617 + /**
47.1618 + * Unpack the start and end times from an array of bytes. This is required
47.1619 + * as of serial version 2.
47.1620 + */
47.1621 + private void unpackTimes(int[] times) {
47.1622 + startTime = times[0];
47.1623 + endTime = times[1];
47.1624 + }
47.1625 +
47.1626 + /**
47.1627 + * Save the state of this object to a stream (i.e., serialize it).
47.1628 + *
47.1629 + * @serialData We write out two formats, a JDK 1.1 compatible format, using
47.1630 + * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
47.1631 + * by the full rules, in packed format, in the optional section. The
47.1632 + * optional section will be ignored by JDK 1.1 code upon stream in.
47.1633 + * <p> Contents of the optional section: The length of a byte array is
47.1634 + * emitted (int); this is 4 as of this release. The byte array of the given
47.1635 + * length is emitted. The contents of the byte array are the true values of
47.1636 + * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
47.1637 + * <code>endDay</code>, and <code>endDayOfWeek</code>. The values of these
47.1638 + * fields in the required section are approximate values suited to the rule
47.1639 + * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
47.1640 + * JDK 1.1.
47.1641 + */
47.1642 + private void writeObject(ObjectOutputStream stream)
47.1643 + throws IOException
47.1644 + {
47.1645 + // Construct a binary rule
47.1646 + byte[] rules = packRules();
47.1647 + int[] times = packTimes();
47.1648 +
47.1649 + // Convert to 1.1 FCS rules. This step may cause us to lose information.
47.1650 + makeRulesCompatible();
47.1651 +
47.1652 + // Write out the 1.1 FCS rules
47.1653 + stream.defaultWriteObject();
47.1654 +
47.1655 + // Write out the binary rules in the optional data area of the stream.
47.1656 + stream.writeInt(rules.length);
47.1657 + stream.write(rules);
47.1658 + stream.writeObject(times);
47.1659 +
47.1660 + // Recover the original rules. This recovers the information lost
47.1661 + // by makeRulesCompatible.
47.1662 + unpackRules(rules);
47.1663 + unpackTimes(times);
47.1664 + }
47.1665 +
47.1666 + /**
47.1667 + * Reconstitute this object from a stream (i.e., deserialize it).
47.1668 + *
47.1669 + * We handle both JDK 1.1
47.1670 + * binary formats and full formats with a packed byte array.
47.1671 + */
47.1672 + private void readObject(ObjectInputStream stream)
47.1673 + throws IOException, ClassNotFoundException
47.1674 + {
47.1675 + stream.defaultReadObject();
47.1676 +
47.1677 + if (serialVersionOnStream < 1) {
47.1678 + // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
47.1679 + // startDayOfWeek and endDayOfWeek were usually uninitialized. We can't do
47.1680 + // too much, so we assume SUNDAY, which actually works most of the time.
47.1681 + if (startDayOfWeek == 0) {
47.1682 + startDayOfWeek = Calendar.SUNDAY;
47.1683 + }
47.1684 + if (endDayOfWeek == 0) {
47.1685 + endDayOfWeek = Calendar.SUNDAY;
47.1686 + }
47.1687 +
47.1688 + // The variables dstSavings, startMode, and endMode are post-1.1, so they
47.1689 + // won't be present if we're reading from a 1.1 stream. Fix them up.
47.1690 + startMode = endMode = DOW_IN_MONTH_MODE;
47.1691 + dstSavings = millisPerHour;
47.1692 + } else {
47.1693 + // For 1.1.4, in addition to the 3 new instance variables, we also
47.1694 + // store the actual rules (which have not be made compatible with 1.1)
47.1695 + // in the optional area. Read them in here and parse them.
47.1696 + int length = stream.readInt();
47.1697 + byte[] rules = new byte[length];
47.1698 + stream.readFully(rules);
47.1699 + unpackRules(rules);
47.1700 + }
47.1701 +
47.1702 + if (serialVersionOnStream >= 2) {
47.1703 + int[] times = (int[]) stream.readObject();
47.1704 + unpackTimes(times);
47.1705 + }
47.1706 +
47.1707 + serialVersionOnStream = currentSerialVersion;
47.1708 + }
47.1709 +}
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/rt/emul/compact/src/main/java/java/util/TimeZone.java Thu Oct 03 15:40:35 2013 +0200
48.3 @@ -0,0 +1,864 @@
48.4 +/*
48.5 + * Copyright (c) 1996, 2011, 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 - All Rights Reserved
48.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
48.32 + *
48.33 + * The original version of this source code and documentation is copyrighted
48.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
48.35 + * materials are provided under terms of a License Agreement between Taligent
48.36 + * and Sun. This technology is protected by multiple US and International
48.37 + * patents. This notice and attribution to Taligent may not be removed.
48.38 + * Taligent is a registered trademark of Taligent, Inc.
48.39 + *
48.40 + */
48.41 +
48.42 +package java.util;
48.43 +
48.44 +import java.io.Serializable;
48.45 +import java.lang.ref.SoftReference;
48.46 +import java.security.AccessController;
48.47 +import java.security.PrivilegedAction;
48.48 +import java.util.concurrent.ConcurrentHashMap;
48.49 +import sun.security.action.GetPropertyAction;
48.50 +import sun.util.TimeZoneNameUtility;
48.51 +import sun.util.calendar.ZoneInfo;
48.52 +import sun.util.calendar.ZoneInfoFile;
48.53 +
48.54 +/**
48.55 + * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
48.56 + * savings.
48.57 + *
48.58 + * <p>
48.59 + * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
48.60 + * which creates a <code>TimeZone</code> based on the time zone where the program
48.61 + * is running. For example, for a program running in Japan, <code>getDefault</code>
48.62 + * creates a <code>TimeZone</code> object based on Japanese Standard Time.
48.63 + *
48.64 + * <p>
48.65 + * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
48.66 + * along with a time zone ID. For instance, the time zone ID for the
48.67 + * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
48.68 + * U.S. Pacific Time <code>TimeZone</code> object with:
48.69 + * <blockquote><pre>
48.70 + * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
48.71 + * </pre></blockquote>
48.72 + * You can use the <code>getAvailableIDs</code> method to iterate through
48.73 + * all the supported time zone IDs. You can then choose a
48.74 + * supported ID to get a <code>TimeZone</code>.
48.75 + * If the time zone you want is not represented by one of the
48.76 + * supported IDs, then a custom time zone ID can be specified to
48.77 + * produce a TimeZone. The syntax of a custom time zone ID is:
48.78 + *
48.79 + * <blockquote><pre>
48.80 + * <a name="CustomID"><i>CustomID:</i></a>
48.81 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
48.82 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
48.83 + * <code>GMT</code> <i>Sign</i> <i>Hours</i>
48.84 + * <i>Sign:</i> one of
48.85 + * <code>+ -</code>
48.86 + * <i>Hours:</i>
48.87 + * <i>Digit</i>
48.88 + * <i>Digit</i> <i>Digit</i>
48.89 + * <i>Minutes:</i>
48.90 + * <i>Digit</i> <i>Digit</i>
48.91 + * <i>Digit:</i> one of
48.92 + * <code>0 1 2 3 4 5 6 7 8 9</code>
48.93 + * </pre></blockquote>
48.94 + *
48.95 + * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
48.96 + * between 00 to 59. For example, "GMT+10" and "GMT+0010" mean ten
48.97 + * hours and ten minutes ahead of GMT, respectively.
48.98 + * <p>
48.99 + * The format is locale independent and digits must be taken from the
48.100 + * Basic Latin block of the Unicode standard. No daylight saving time
48.101 + * transition schedule can be specified with a custom time zone ID. If
48.102 + * the specified string doesn't match the syntax, <code>"GMT"</code>
48.103 + * is used.
48.104 + * <p>
48.105 + * When creating a <code>TimeZone</code>, the specified custom time
48.106 + * zone ID is normalized in the following syntax:
48.107 + * <blockquote><pre>
48.108 + * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
48.109 + * <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
48.110 + * <i>Sign:</i> one of
48.111 + * <code>+ -</code>
48.112 + * <i>TwoDigitHours:</i>
48.113 + * <i>Digit</i> <i>Digit</i>
48.114 + * <i>Minutes:</i>
48.115 + * <i>Digit</i> <i>Digit</i>
48.116 + * <i>Digit:</i> one of
48.117 + * <code>0 1 2 3 4 5 6 7 8 9</code>
48.118 + * </pre></blockquote>
48.119 + * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
48.120 + *
48.121 + * <h4>Three-letter time zone IDs</h4>
48.122 + *
48.123 + * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
48.124 + * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
48.125 + * use is deprecated</strong> because the same abbreviation is often used
48.126 + * for multiple time zones (for example, "CST" could be U.S. "Central Standard
48.127 + * Time" and "China Standard Time"), and the Java platform can then only
48.128 + * recognize one of them.
48.129 + *
48.130 + *
48.131 + * @see Calendar
48.132 + * @see GregorianCalendar
48.133 + * @see SimpleTimeZone
48.134 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
48.135 + * @since JDK1.1
48.136 + */
48.137 +abstract public class TimeZone implements Serializable, Cloneable {
48.138 + /**
48.139 + * Sole constructor. (For invocation by subclass constructors, typically
48.140 + * implicit.)
48.141 + */
48.142 + public TimeZone() {
48.143 + }
48.144 +
48.145 + /**
48.146 + * A style specifier for <code>getDisplayName()</code> indicating
48.147 + * a short name, such as "PST."
48.148 + * @see #LONG
48.149 + * @since 1.2
48.150 + */
48.151 + public static final int SHORT = 0;
48.152 +
48.153 + /**
48.154 + * A style specifier for <code>getDisplayName()</code> indicating
48.155 + * a long name, such as "Pacific Standard Time."
48.156 + * @see #SHORT
48.157 + * @since 1.2
48.158 + */
48.159 + public static final int LONG = 1;
48.160 +
48.161 + // Constants used internally; unit is milliseconds
48.162 + private static final int ONE_MINUTE = 60*1000;
48.163 + private static final int ONE_HOUR = 60*ONE_MINUTE;
48.164 + private static final int ONE_DAY = 24*ONE_HOUR;
48.165 +
48.166 + // Proclaim serialization compatibility with JDK 1.1
48.167 + static final long serialVersionUID = 3581463369166924961L;
48.168 +
48.169 + /**
48.170 + * Gets the time zone offset, for current date, modified in case of
48.171 + * daylight savings. This is the offset to add to UTC to get local time.
48.172 + * <p>
48.173 + * This method returns a historically correct offset if an
48.174 + * underlying <code>TimeZone</code> implementation subclass
48.175 + * supports historical Daylight Saving Time schedule and GMT
48.176 + * offset changes.
48.177 + *
48.178 + * @param era the era of the given date.
48.179 + * @param year the year in the given date.
48.180 + * @param month the month in the given date.
48.181 + * Month is 0-based. e.g., 0 for January.
48.182 + * @param day the day-in-month of the given date.
48.183 + * @param dayOfWeek the day-of-week of the given date.
48.184 + * @param milliseconds the milliseconds in day in <em>standard</em>
48.185 + * local time.
48.186 + *
48.187 + * @return the offset in milliseconds to add to GMT to get local time.
48.188 + *
48.189 + * @see Calendar#ZONE_OFFSET
48.190 + * @see Calendar#DST_OFFSET
48.191 + */
48.192 + public abstract int getOffset(int era, int year, int month, int day,
48.193 + int dayOfWeek, int milliseconds);
48.194 +
48.195 + /**
48.196 + * Returns the offset of this time zone from UTC at the specified
48.197 + * date. If Daylight Saving Time is in effect at the specified
48.198 + * date, the offset value is adjusted with the amount of daylight
48.199 + * saving.
48.200 + * <p>
48.201 + * This method returns a historically correct offset value if an
48.202 + * underlying TimeZone implementation subclass supports historical
48.203 + * Daylight Saving Time schedule and GMT offset changes.
48.204 + *
48.205 + * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
48.206 + * @return the amount of time in milliseconds to add to UTC to get local time.
48.207 + *
48.208 + * @see Calendar#ZONE_OFFSET
48.209 + * @see Calendar#DST_OFFSET
48.210 + * @since 1.4
48.211 + */
48.212 + public int getOffset(long date) {
48.213 + if (inDaylightTime(new Date(date))) {
48.214 + return getRawOffset() + getDSTSavings();
48.215 + }
48.216 + return getRawOffset();
48.217 + }
48.218 +
48.219 + /**
48.220 + * Gets the raw GMT offset and the amount of daylight saving of this
48.221 + * time zone at the given time.
48.222 + * @param date the milliseconds (since January 1, 1970,
48.223 + * 00:00:00.000 GMT) at which the time zone offset and daylight
48.224 + * saving amount are found
48.225 + * @param offset an array of int where the raw GMT offset
48.226 + * (offset[0]) and daylight saving amount (offset[1]) are stored,
48.227 + * or null if those values are not needed. The method assumes that
48.228 + * the length of the given array is two or larger.
48.229 + * @return the total amount of the raw GMT offset and daylight
48.230 + * saving at the specified date.
48.231 + *
48.232 + * @see Calendar#ZONE_OFFSET
48.233 + * @see Calendar#DST_OFFSET
48.234 + */
48.235 + int getOffsets(long date, int[] offsets) {
48.236 + int rawoffset = getRawOffset();
48.237 + int dstoffset = 0;
48.238 + if (inDaylightTime(new Date(date))) {
48.239 + dstoffset = getDSTSavings();
48.240 + }
48.241 + if (offsets != null) {
48.242 + offsets[0] = rawoffset;
48.243 + offsets[1] = dstoffset;
48.244 + }
48.245 + return rawoffset + dstoffset;
48.246 + }
48.247 +
48.248 + /**
48.249 + * Sets the base time zone offset to GMT.
48.250 + * This is the offset to add to UTC to get local time.
48.251 + * <p>
48.252 + * If an underlying <code>TimeZone</code> implementation subclass
48.253 + * supports historical GMT offset changes, the specified GMT
48.254 + * offset is set as the latest GMT offset and the difference from
48.255 + * the known latest GMT offset value is used to adjust all
48.256 + * historical GMT offset values.
48.257 + *
48.258 + * @param offsetMillis the given base time zone offset to GMT.
48.259 + */
48.260 + abstract public void setRawOffset(int offsetMillis);
48.261 +
48.262 + /**
48.263 + * Returns the amount of time in milliseconds to add to UTC to get
48.264 + * standard time in this time zone. Because this value is not
48.265 + * affected by daylight saving time, it is called <I>raw
48.266 + * offset</I>.
48.267 + * <p>
48.268 + * If an underlying <code>TimeZone</code> implementation subclass
48.269 + * supports historical GMT offset changes, the method returns the
48.270 + * raw offset value of the current date. In Honolulu, for example,
48.271 + * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
48.272 + * this method always returns -36000000 milliseconds (i.e., -10
48.273 + * hours).
48.274 + *
48.275 + * @return the amount of raw offset time in milliseconds to add to UTC.
48.276 + * @see Calendar#ZONE_OFFSET
48.277 + */
48.278 + public abstract int getRawOffset();
48.279 +
48.280 + /**
48.281 + * Gets the ID of this time zone.
48.282 + * @return the ID of this time zone.
48.283 + */
48.284 + public String getID()
48.285 + {
48.286 + return ID;
48.287 + }
48.288 +
48.289 + /**
48.290 + * Sets the time zone ID. This does not change any other data in
48.291 + * the time zone object.
48.292 + * @param ID the new time zone ID.
48.293 + */
48.294 + public void setID(String ID)
48.295 + {
48.296 + if (ID == null) {
48.297 + throw new NullPointerException();
48.298 + }
48.299 + this.ID = ID;
48.300 + }
48.301 +
48.302 + /**
48.303 + * Returns a long standard time name of this {@code TimeZone} suitable for
48.304 + * presentation to the user in the default locale.
48.305 + *
48.306 + * <p>This method is equivalent to:
48.307 + * <pre><blockquote>
48.308 + * getDisplayName(false, {@link #LONG},
48.309 + * Locale.getDefault({@link Locale.Category#DISPLAY}))
48.310 + * </blockquote></pre>
48.311 + *
48.312 + * @return the human-readable name of this time zone in the default locale.
48.313 + * @since 1.2
48.314 + * @see #getDisplayName(boolean, int, Locale)
48.315 + * @see Locale#getDefault(Locale.Category)
48.316 + * @see Locale.Category
48.317 + */
48.318 + public final String getDisplayName() {
48.319 + return getDisplayName(false, LONG,
48.320 + Locale.getDefault(Locale.Category.DISPLAY));
48.321 + }
48.322 +
48.323 + /**
48.324 + * Returns a long standard time name of this {@code TimeZone} suitable for
48.325 + * presentation to the user in the specified {@code locale}.
48.326 + *
48.327 + * <p>This method is equivalent to:
48.328 + * <pre><blockquote>
48.329 + * getDisplayName(false, {@link #LONG}, locale)
48.330 + * </blockquote></pre>
48.331 + *
48.332 + * @param locale the locale in which to supply the display name.
48.333 + * @return the human-readable name of this time zone in the given locale.
48.334 + * @exception NullPointerException if {@code locale} is {@code null}.
48.335 + * @since 1.2
48.336 + * @see #getDisplayName(boolean, int, Locale)
48.337 + */
48.338 + public final String getDisplayName(Locale locale) {
48.339 + return getDisplayName(false, LONG, locale);
48.340 + }
48.341 +
48.342 + /**
48.343 + * Returns a name in the specified {@code style} of this {@code TimeZone}
48.344 + * suitable for presentation to the user in the default locale. If the
48.345 + * specified {@code daylight} is {@code true}, a Daylight Saving Time name
48.346 + * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
48.347 + * Time). Otherwise, a Standard Time name is returned.
48.348 + *
48.349 + * <p>This method is equivalent to:
48.350 + * <pre><blockquote>
48.351 + * getDisplayName(daylight, style,
48.352 + * Locale.getDefault({@link Locale.Category#DISPLAY}))
48.353 + * </blockquote></pre>
48.354 + *
48.355 + * @param daylight {@code true} specifying a Daylight Saving Time name, or
48.356 + * {@code false} specifying a Standard Time name
48.357 + * @param style either {@link #LONG} or {@link #SHORT}
48.358 + * @return the human-readable name of this time zone in the default locale.
48.359 + * @exception IllegalArgumentException if {@code style} is invalid.
48.360 + * @since 1.2
48.361 + * @see #getDisplayName(boolean, int, Locale)
48.362 + * @see Locale#getDefault(Locale.Category)
48.363 + * @see Locale.Category
48.364 + * @see java.text.DateFormatSymbols#getZoneStrings()
48.365 + */
48.366 + public final String getDisplayName(boolean daylight, int style) {
48.367 + return getDisplayName(daylight, style,
48.368 + Locale.getDefault(Locale.Category.DISPLAY));
48.369 + }
48.370 +
48.371 + /**
48.372 + * Returns a name in the specified {@code style} of this {@code TimeZone}
48.373 + * suitable for presentation to the user in the specified {@code
48.374 + * locale}. If the specified {@code daylight} is {@code true}, a Daylight
48.375 + * Saving Time name is returned (even if this {@code TimeZone} doesn't
48.376 + * observe Daylight Saving Time). Otherwise, a Standard Time name is
48.377 + * returned.
48.378 + *
48.379 + * <p>When looking up a time zone name, the {@linkplain
48.380 + * ResourceBundle.Control#getCandidateLocales(String,Locale) default
48.381 + * <code>Locale</code> search path of <code>ResourceBundle</code>} derived
48.382 + * from the specified {@code locale} is used. (No {@linkplain
48.383 + * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
48.384 + * <code>Locale</code>} search is performed.) If a time zone name in any
48.385 + * {@code Locale} of the search path, including {@link Locale#ROOT}, is
48.386 + * found, the name is returned. Otherwise, a string in the
48.387 + * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned.
48.388 + *
48.389 + * @param daylight {@code true} specifying a Daylight Saving Time name, or
48.390 + * {@code false} specifying a Standard Time name
48.391 + * @param style either {@link #LONG} or {@link #SHORT}
48.392 + * @param locale the locale in which to supply the display name.
48.393 + * @return the human-readable name of this time zone in the given locale.
48.394 + * @exception IllegalArgumentException if {@code style} is invalid.
48.395 + * @exception NullPointerException if {@code locale} is {@code null}.
48.396 + * @since 1.2
48.397 + * @see java.text.DateFormatSymbols#getZoneStrings()
48.398 + */
48.399 + public String getDisplayName(boolean daylight, int style, Locale locale) {
48.400 + if (style != SHORT && style != LONG) {
48.401 + throw new IllegalArgumentException("Illegal style: " + style);
48.402 + }
48.403 +
48.404 + String id = getID();
48.405 + String[] names = getDisplayNames(id, locale);
48.406 + if (names == null) {
48.407 + if (id.startsWith("GMT")) {
48.408 + char sign = id.charAt(3);
48.409 + if (sign == '+' || sign == '-') {
48.410 + return id;
48.411 + }
48.412 + }
48.413 + int offset = getRawOffset();
48.414 + if (daylight) {
48.415 + offset += getDSTSavings();
48.416 + }
48.417 + return ZoneInfoFile.toCustomID(offset);
48.418 + }
48.419 +
48.420 + int index = daylight ? 3 : 1;
48.421 + if (style == SHORT) {
48.422 + index++;
48.423 + }
48.424 + return names[index];
48.425 + }
48.426 +
48.427 + private static class DisplayNames {
48.428 + // Cache for managing display names per timezone per locale
48.429 + // The structure is:
48.430 + // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
48.431 + private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
48.432 + new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
48.433 + }
48.434 +
48.435 + private static final String[] getDisplayNames(String id, Locale locale) {
48.436 + Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
48.437 +
48.438 + SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
48.439 + if (ref != null) {
48.440 + Map<Locale, String[]> perLocale = ref.get();
48.441 + if (perLocale != null) {
48.442 + String[] names = perLocale.get(locale);
48.443 + if (names != null) {
48.444 + return names;
48.445 + }
48.446 + names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
48.447 + if (names != null) {
48.448 + perLocale.put(locale, names);
48.449 + }
48.450 + return names;
48.451 + }
48.452 + }
48.453 +
48.454 + String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
48.455 + if (names != null) {
48.456 + Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
48.457 + perLocale.put(locale, names);
48.458 + ref = new SoftReference<Map<Locale, String[]>>(perLocale);
48.459 + displayNames.put(id, ref);
48.460 + }
48.461 + return names;
48.462 + }
48.463 +
48.464 + /**
48.465 + * Returns the amount of time to be added to local standard time
48.466 + * to get local wall clock time.
48.467 + *
48.468 + * <p>The default implementation returns 3600000 milliseconds
48.469 + * (i.e., one hour) if a call to {@link #useDaylightTime()}
48.470 + * returns {@code true}. Otherwise, 0 (zero) is returned.
48.471 + *
48.472 + * <p>If an underlying {@code TimeZone} implementation subclass
48.473 + * supports historical and future Daylight Saving Time schedule
48.474 + * changes, this method returns the amount of saving time of the
48.475 + * last known Daylight Saving Time rule that can be a future
48.476 + * prediction.
48.477 + *
48.478 + * <p>If the amount of saving time at any given time stamp is
48.479 + * required, construct a {@link Calendar} with this {@code
48.480 + * TimeZone} and the time stamp, and call {@link Calendar#get(int)
48.481 + * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
48.482 + *
48.483 + * @return the amount of saving time in milliseconds
48.484 + * @since 1.4
48.485 + * @see #inDaylightTime(Date)
48.486 + * @see #getOffset(long)
48.487 + * @see #getOffset(int,int,int,int,int,int)
48.488 + * @see Calendar#ZONE_OFFSET
48.489 + */
48.490 + public int getDSTSavings() {
48.491 + if (useDaylightTime()) {
48.492 + return 3600000;
48.493 + }
48.494 + return 0;
48.495 + }
48.496 +
48.497 + /**
48.498 + * Queries if this {@code TimeZone} uses Daylight Saving Time.
48.499 + *
48.500 + * <p>If an underlying {@code TimeZone} implementation subclass
48.501 + * supports historical and future Daylight Saving Time schedule
48.502 + * changes, this method refers to the last known Daylight Saving Time
48.503 + * rule that can be a future prediction and may not be the same as
48.504 + * the current rule. Consider calling {@link #observesDaylightTime()}
48.505 + * if the current rule should also be taken into account.
48.506 + *
48.507 + * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
48.508 + * {@code false}, otherwise.
48.509 + * @see #inDaylightTime(Date)
48.510 + * @see Calendar#DST_OFFSET
48.511 + */
48.512 + public abstract boolean useDaylightTime();
48.513 +
48.514 + /**
48.515 + * Returns {@code true} if this {@code TimeZone} is currently in
48.516 + * Daylight Saving Time, or if a transition from Standard Time to
48.517 + * Daylight Saving Time occurs at any future time.
48.518 + *
48.519 + * <p>The default implementation returns {@code true} if
48.520 + * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
48.521 + * returns {@code true}.
48.522 + *
48.523 + * @return {@code true} if this {@code TimeZone} is currently in
48.524 + * Daylight Saving Time, or if a transition from Standard Time to
48.525 + * Daylight Saving Time occurs at any future time; {@code false}
48.526 + * otherwise.
48.527 + * @since 1.7
48.528 + * @see #useDaylightTime()
48.529 + * @see #inDaylightTime(Date)
48.530 + * @see Calendar#DST_OFFSET
48.531 + */
48.532 + public boolean observesDaylightTime() {
48.533 + return useDaylightTime() || inDaylightTime(new Date());
48.534 + }
48.535 +
48.536 + /**
48.537 + * Queries if the given {@code date} is in Daylight Saving Time in
48.538 + * this time zone.
48.539 + *
48.540 + * @param date the given Date.
48.541 + * @return {@code true} if the given date is in Daylight Saving Time,
48.542 + * {@code false}, otherwise.
48.543 + */
48.544 + abstract public boolean inDaylightTime(Date date);
48.545 +
48.546 + /**
48.547 + * Gets the <code>TimeZone</code> for the given ID.
48.548 + *
48.549 + * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
48.550 + * such as "PST", a full name such as "America/Los_Angeles", or a custom
48.551 + * ID such as "GMT-8:00". Note that the support of abbreviations is
48.552 + * for JDK 1.1.x compatibility only and full names should be used.
48.553 + *
48.554 + * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
48.555 + * cannot be understood.
48.556 + */
48.557 + public static synchronized TimeZone getTimeZone(String ID) {
48.558 + return getTimeZone(ID, true);
48.559 + }
48.560 +
48.561 + private static TimeZone getTimeZone(String ID, boolean fallback) {
48.562 + TimeZone tz = ZoneInfo.getTimeZone(ID);
48.563 + if (tz == null) {
48.564 + tz = parseCustomTimeZone(ID);
48.565 + if (tz == null && fallback) {
48.566 + tz = new ZoneInfo(GMT_ID, 0);
48.567 + }
48.568 + }
48.569 + return tz;
48.570 + }
48.571 +
48.572 + /**
48.573 + * Gets the available IDs according to the given time zone offset in milliseconds.
48.574 + *
48.575 + * @param rawOffset the given time zone GMT offset in milliseconds.
48.576 + * @return an array of IDs, where the time zone for that ID has
48.577 + * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
48.578 + * both have GMT-07:00, but differ in daylight saving behavior.
48.579 + * @see #getRawOffset()
48.580 + */
48.581 + public static synchronized String[] getAvailableIDs(int rawOffset) {
48.582 + return ZoneInfo.getAvailableIDs(rawOffset);
48.583 + }
48.584 +
48.585 + /**
48.586 + * Gets all the available IDs supported.
48.587 + * @return an array of IDs.
48.588 + */
48.589 + public static synchronized String[] getAvailableIDs() {
48.590 + return ZoneInfo.getAvailableIDs();
48.591 + }
48.592 +
48.593 + /**
48.594 + * Gets the platform defined TimeZone ID.
48.595 + **/
48.596 + private static native String getSystemTimeZoneID(String javaHome,
48.597 + String country);
48.598 +
48.599 + /**
48.600 + * Gets the custom time zone ID based on the GMT offset of the
48.601 + * platform. (e.g., "GMT+08:00")
48.602 + */
48.603 + private static native String getSystemGMTOffsetID();
48.604 +
48.605 + /**
48.606 + * Gets the default <code>TimeZone</code> for this host.
48.607 + * The source of the default <code>TimeZone</code>
48.608 + * may vary with implementation.
48.609 + * @return a default <code>TimeZone</code>.
48.610 + * @see #setDefault
48.611 + */
48.612 + public static TimeZone getDefault() {
48.613 + return (TimeZone) getDefaultRef().clone();
48.614 + }
48.615 +
48.616 + /**
48.617 + * Returns the reference to the default TimeZone object. This
48.618 + * method doesn't create a clone.
48.619 + */
48.620 + static TimeZone getDefaultRef() {
48.621 + TimeZone defaultZone = defaultZoneTL.get();
48.622 + if (defaultZone == null) {
48.623 + defaultZone = defaultTimeZone;
48.624 + if (defaultZone == null) {
48.625 + // Need to initialize the default time zone.
48.626 + defaultZone = setDefaultZone();
48.627 + assert defaultZone != null;
48.628 + }
48.629 + }
48.630 + // Don't clone here.
48.631 + return defaultZone;
48.632 + }
48.633 +
48.634 + private static synchronized TimeZone setDefaultZone() {
48.635 + TimeZone tz = null;
48.636 + // get the time zone ID from the system properties
48.637 + String zoneID = AccessController.doPrivileged(
48.638 + new GetPropertyAction("user.timezone"));
48.639 +
48.640 + // if the time zone ID is not set (yet), perform the
48.641 + // platform to Java time zone ID mapping.
48.642 + if (zoneID == null || zoneID.equals("")) {
48.643 + String country = AccessController.doPrivileged(
48.644 + new GetPropertyAction("user.country"));
48.645 + String javaHome = AccessController.doPrivileged(
48.646 + new GetPropertyAction("java.home"));
48.647 + try {
48.648 + zoneID = getSystemTimeZoneID(javaHome, country);
48.649 + if (zoneID == null) {
48.650 + zoneID = GMT_ID;
48.651 + }
48.652 + } catch (NullPointerException e) {
48.653 + zoneID = GMT_ID;
48.654 + }
48.655 + }
48.656 +
48.657 + // Get the time zone for zoneID. But not fall back to
48.658 + // "GMT" here.
48.659 + tz = getTimeZone(zoneID, false);
48.660 +
48.661 + if (tz == null) {
48.662 + // If the given zone ID is unknown in Java, try to
48.663 + // get the GMT-offset-based time zone ID,
48.664 + // a.k.a. custom time zone ID (e.g., "GMT-08:00").
48.665 + String gmtOffsetID = getSystemGMTOffsetID();
48.666 + if (gmtOffsetID != null) {
48.667 + zoneID = gmtOffsetID;
48.668 + }
48.669 + tz = getTimeZone(zoneID, true);
48.670 + }
48.671 + assert tz != null;
48.672 +
48.673 + final String id = zoneID;
48.674 + AccessController.doPrivileged(new PrivilegedAction<Object>() {
48.675 + public Object run() {
48.676 + System.setProperty("user.timezone", id);
48.677 + return null;
48.678 + }
48.679 + });
48.680 +
48.681 + defaultTimeZone = tz;
48.682 + return tz;
48.683 + }
48.684 +
48.685 + private static boolean hasPermission() {
48.686 + boolean hasPermission = true;
48.687 + SecurityManager sm = System.getSecurityManager();
48.688 + if (sm != null) {
48.689 + try {
48.690 + sm.checkPermission(new PropertyPermission
48.691 + ("user.timezone", "write"));
48.692 + } catch (SecurityException e) {
48.693 + hasPermission = false;
48.694 + }
48.695 + }
48.696 + return hasPermission;
48.697 + }
48.698 +
48.699 + /**
48.700 + * Sets the <code>TimeZone</code> that is
48.701 + * returned by the <code>getDefault</code> method. If <code>zone</code>
48.702 + * is null, reset the default to the value it had originally when the
48.703 + * VM first started.
48.704 + * @param zone the new default time zone
48.705 + * @see #getDefault
48.706 + */
48.707 + public static void setDefault(TimeZone zone)
48.708 + {
48.709 + if (hasPermission()) {
48.710 + synchronized (TimeZone.class) {
48.711 + defaultTimeZone = zone;
48.712 + defaultZoneTL.set(null);
48.713 + }
48.714 + } else {
48.715 + defaultZoneTL.set(zone);
48.716 + }
48.717 + }
48.718 +
48.719 + /**
48.720 + * Returns true if this zone has the same rule and offset as another zone.
48.721 + * That is, if this zone differs only in ID, if at all. Returns false
48.722 + * if the other zone is null.
48.723 + * @param other the <code>TimeZone</code> object to be compared with
48.724 + * @return true if the other zone is not null and is the same as this one,
48.725 + * with the possible exception of the ID
48.726 + * @since 1.2
48.727 + */
48.728 + public boolean hasSameRules(TimeZone other) {
48.729 + return other != null && getRawOffset() == other.getRawOffset() &&
48.730 + useDaylightTime() == other.useDaylightTime();
48.731 + }
48.732 +
48.733 + /**
48.734 + * Creates a copy of this <code>TimeZone</code>.
48.735 + *
48.736 + * @return a clone of this <code>TimeZone</code>
48.737 + */
48.738 + public Object clone()
48.739 + {
48.740 + try {
48.741 + TimeZone other = (TimeZone) super.clone();
48.742 + other.ID = ID;
48.743 + return other;
48.744 + } catch (CloneNotSupportedException e) {
48.745 + throw new InternalError();
48.746 + }
48.747 + }
48.748 +
48.749 + /**
48.750 + * The null constant as a TimeZone.
48.751 + */
48.752 + static final TimeZone NO_TIMEZONE = null;
48.753 +
48.754 + // =======================privates===============================
48.755 +
48.756 + /**
48.757 + * The string identifier of this <code>TimeZone</code>. This is a
48.758 + * programmatic identifier used internally to look up <code>TimeZone</code>
48.759 + * objects from the system table and also to map them to their localized
48.760 + * display names. <code>ID</code> values are unique in the system
48.761 + * table but may not be for dynamically created zones.
48.762 + * @serial
48.763 + */
48.764 + private String ID;
48.765 + private static volatile TimeZone defaultTimeZone;
48.766 + private static final InheritableThreadLocal<TimeZone> defaultZoneTL
48.767 + = new InheritableThreadLocal<TimeZone>();
48.768 +
48.769 + static final String GMT_ID = "GMT";
48.770 + private static final int GMT_ID_LENGTH = 3;
48.771 +
48.772 + /**
48.773 + * Parses a custom time zone identifier and returns a corresponding zone.
48.774 + * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
48.775 + *
48.776 + * @param id a string of the <a href="#CustomID">custom ID form</a>.
48.777 + * @return a newly created TimeZone with the given offset and
48.778 + * no daylight saving time, or null if the id cannot be parsed.
48.779 + */
48.780 + private static final TimeZone parseCustomTimeZone(String id) {
48.781 + int length;
48.782 +
48.783 + // Error if the length of id isn't long enough or id doesn't
48.784 + // start with "GMT".
48.785 + if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
48.786 + id.indexOf(GMT_ID) != 0) {
48.787 + return null;
48.788 + }
48.789 +
48.790 + ZoneInfo zi;
48.791 +
48.792 + // First, we try to find it in the cache with the given
48.793 + // id. Even the id is not normalized, the returned ZoneInfo
48.794 + // should have its normalized id.
48.795 + zi = ZoneInfoFile.getZoneInfo(id);
48.796 + if (zi != null) {
48.797 + return zi;
48.798 + }
48.799 +
48.800 + int index = GMT_ID_LENGTH;
48.801 + boolean negative = false;
48.802 + char c = id.charAt(index++);
48.803 + if (c == '-') {
48.804 + negative = true;
48.805 + } else if (c != '+') {
48.806 + return null;
48.807 + }
48.808 +
48.809 + int hours = 0;
48.810 + int num = 0;
48.811 + int countDelim = 0;
48.812 + int len = 0;
48.813 + while (index < length) {
48.814 + c = id.charAt(index++);
48.815 + if (c == ':') {
48.816 + if (countDelim > 0) {
48.817 + return null;
48.818 + }
48.819 + if (len > 2) {
48.820 + return null;
48.821 + }
48.822 + hours = num;
48.823 + countDelim++;
48.824 + num = 0;
48.825 + len = 0;
48.826 + continue;
48.827 + }
48.828 + if (c < '0' || c > '9') {
48.829 + return null;
48.830 + }
48.831 + num = num * 10 + (c - '0');
48.832 + len++;
48.833 + }
48.834 + if (index != length) {
48.835 + return null;
48.836 + }
48.837 + if (countDelim == 0) {
48.838 + if (len <= 2) {
48.839 + hours = num;
48.840 + num = 0;
48.841 + } else {
48.842 + hours = num / 100;
48.843 + num %= 100;
48.844 + }
48.845 + } else {
48.846 + if (len != 2) {
48.847 + return null;
48.848 + }
48.849 + }
48.850 + if (hours > 23 || num > 59) {
48.851 + return null;
48.852 + }
48.853 + int gmtOffset = (hours * 60 + num) * 60 * 1000;
48.854 +
48.855 + if (gmtOffset == 0) {
48.856 + zi = ZoneInfoFile.getZoneInfo(GMT_ID);
48.857 + if (negative) {
48.858 + zi.setID("GMT-00:00");
48.859 + } else {
48.860 + zi.setID("GMT+00:00");
48.861 + }
48.862 + } else {
48.863 + zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);
48.864 + }
48.865 + return zi;
48.866 + }
48.867 +}
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java Thu Oct 03 15:40:35 2013 +0200
49.3 @@ -0,0 +1,1522 @@
49.4 +/*
49.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
49.6 + *
49.7 + * This code is free software; you can redistribute it and/or modify it
49.8 + * under the terms of the GNU General Public License version 2 only, as
49.9 + * published by the Free Software Foundation. Oracle designates this
49.10 + * particular file as subject to the "Classpath" exception as provided
49.11 + * by Oracle in the LICENSE file that accompanied this code.
49.12 + *
49.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
49.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
49.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
49.16 + * version 2 for more details (a copy is included in the LICENSE file that
49.17 + * accompanied this code).
49.18 + *
49.19 + * You should have received a copy of the GNU General Public License version
49.20 + * 2 along with this work; if not, write to the Free Software Foundation,
49.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
49.22 + *
49.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
49.24 + * or visit www.oracle.com if you need additional information or have any
49.25 + * questions.
49.26 + */
49.27 +
49.28 +/*
49.29 + * This file is available under and governed by the GNU General Public
49.30 + * License version 2 only, as published by the Free Software Foundation.
49.31 + * However, the following notice accompanied the original version of this
49.32 + * file:
49.33 + *
49.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
49.35 + * Expert Group and released to the public domain, as explained at
49.36 + * http://creativecommons.org/publicdomain/zero/1.0/
49.37 + */
49.38 +
49.39 +package java.util.concurrent;
49.40 +import java.util.concurrent.locks.*;
49.41 +import java.util.*;
49.42 +import java.io.Serializable;
49.43 +import java.io.IOException;
49.44 +import java.io.ObjectInputStream;
49.45 +import java.io.ObjectOutputStream;
49.46 +
49.47 +/**
49.48 + * A hash table supporting full concurrency of retrievals and
49.49 + * adjustable expected concurrency for updates. This class obeys the
49.50 + * same functional specification as {@link java.util.Hashtable}, and
49.51 + * includes versions of methods corresponding to each method of
49.52 + * <tt>Hashtable</tt>. However, even though all operations are
49.53 + * thread-safe, retrieval operations do <em>not</em> entail locking,
49.54 + * and there is <em>not</em> any support for locking the entire table
49.55 + * in a way that prevents all access. This class is fully
49.56 + * interoperable with <tt>Hashtable</tt> in programs that rely on its
49.57 + * thread safety but not on its synchronization details.
49.58 + *
49.59 + * <p> Retrieval operations (including <tt>get</tt>) generally do not
49.60 + * block, so may overlap with update operations (including
49.61 + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results
49.62 + * of the most recently <em>completed</em> update operations holding
49.63 + * upon their onset. For aggregate operations such as <tt>putAll</tt>
49.64 + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or
49.65 + * removal of only some entries. Similarly, Iterators and
49.66 + * Enumerations return elements reflecting the state of the hash table
49.67 + * at some point at or since the creation of the iterator/enumeration.
49.68 + * They do <em>not</em> throw {@link ConcurrentModificationException}.
49.69 + * However, iterators are designed to be used by only one thread at a time.
49.70 + *
49.71 + * <p> The allowed concurrency among update operations is guided by
49.72 + * the optional <tt>concurrencyLevel</tt> constructor argument
49.73 + * (default <tt>16</tt>), which is used as a hint for internal sizing. The
49.74 + * table is internally partitioned to try to permit the indicated
49.75 + * number of concurrent updates without contention. Because placement
49.76 + * in hash tables is essentially random, the actual concurrency will
49.77 + * vary. Ideally, you should choose a value to accommodate as many
49.78 + * threads as will ever concurrently modify the table. Using a
49.79 + * significantly higher value than you need can waste space and time,
49.80 + * and a significantly lower value can lead to thread contention. But
49.81 + * overestimates and underestimates within an order of magnitude do
49.82 + * not usually have much noticeable impact. A value of one is
49.83 + * appropriate when it is known that only one thread will modify and
49.84 + * all others will only read. Also, resizing this or any other kind of
49.85 + * hash table is a relatively slow operation, so, when possible, it is
49.86 + * a good idea to provide estimates of expected table sizes in
49.87 + * constructors.
49.88 + *
49.89 + * <p>This class and its views and iterators implement all of the
49.90 + * <em>optional</em> methods of the {@link Map} and {@link Iterator}
49.91 + * interfaces.
49.92 + *
49.93 + * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
49.94 + * does <em>not</em> allow <tt>null</tt> to be used as a key or value.
49.95 + *
49.96 + * <p>This class is a member of the
49.97 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
49.98 + * Java Collections Framework</a>.
49.99 + *
49.100 + * @since 1.5
49.101 + * @author Doug Lea
49.102 + * @param <K> the type of keys maintained by this map
49.103 + * @param <V> the type of mapped values
49.104 + */
49.105 +public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
49.106 + implements ConcurrentMap<K, V>, Serializable {
49.107 + private static final long serialVersionUID = 7249069246763182397L;
49.108 +
49.109 + /*
49.110 + * The basic strategy is to subdivide the table among Segments,
49.111 + * each of which itself is a concurrently readable hash table. To
49.112 + * reduce footprint, all but one segments are constructed only
49.113 + * when first needed (see ensureSegment). To maintain visibility
49.114 + * in the presence of lazy construction, accesses to segments as
49.115 + * well as elements of segment's table must use volatile access,
49.116 + * which is done via Unsafe within methods segmentAt etc
49.117 + * below. These provide the functionality of AtomicReferenceArrays
49.118 + * but reduce the levels of indirection. Additionally,
49.119 + * volatile-writes of table elements and entry "next" fields
49.120 + * within locked operations use the cheaper "lazySet" forms of
49.121 + * writes (via putOrderedObject) because these writes are always
49.122 + * followed by lock releases that maintain sequential consistency
49.123 + * of table updates.
49.124 + *
49.125 + * Historical note: The previous version of this class relied
49.126 + * heavily on "final" fields, which avoided some volatile reads at
49.127 + * the expense of a large initial footprint. Some remnants of
49.128 + * that design (including forced construction of segment 0) exist
49.129 + * to ensure serialization compatibility.
49.130 + */
49.131 +
49.132 + /* ---------------- Constants -------------- */
49.133 +
49.134 + /**
49.135 + * The default initial capacity for this table,
49.136 + * used when not otherwise specified in a constructor.
49.137 + */
49.138 + static final int DEFAULT_INITIAL_CAPACITY = 16;
49.139 +
49.140 + /**
49.141 + * The default load factor for this table, used when not
49.142 + * otherwise specified in a constructor.
49.143 + */
49.144 + static final float DEFAULT_LOAD_FACTOR = 0.75f;
49.145 +
49.146 + /**
49.147 + * The default concurrency level for this table, used when not
49.148 + * otherwise specified in a constructor.
49.149 + */
49.150 + static final int DEFAULT_CONCURRENCY_LEVEL = 16;
49.151 +
49.152 + /**
49.153 + * The maximum capacity, used if a higher value is implicitly
49.154 + * specified by either of the constructors with arguments. MUST
49.155 + * be a power of two <= 1<<30 to ensure that entries are indexable
49.156 + * using ints.
49.157 + */
49.158 + static final int MAXIMUM_CAPACITY = 1 << 30;
49.159 +
49.160 + /**
49.161 + * The minimum capacity for per-segment tables. Must be a power
49.162 + * of two, at least two to avoid immediate resizing on next use
49.163 + * after lazy construction.
49.164 + */
49.165 + static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
49.166 +
49.167 + /**
49.168 + * The maximum number of segments to allow; used to bound
49.169 + * constructor arguments. Must be power of two less than 1 << 24.
49.170 + */
49.171 + static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
49.172 +
49.173 + /**
49.174 + * Number of unsynchronized retries in size and containsValue
49.175 + * methods before resorting to locking. This is used to avoid
49.176 + * unbounded retries if tables undergo continuous modification
49.177 + * which would make it impossible to obtain an accurate result.
49.178 + */
49.179 + static final int RETRIES_BEFORE_LOCK = 2;
49.180 +
49.181 + /* ---------------- Fields -------------- */
49.182 +
49.183 + /**
49.184 + * Mask value for indexing into segments. The upper bits of a
49.185 + * key's hash code are used to choose the segment.
49.186 + */
49.187 + final int segmentMask;
49.188 +
49.189 + /**
49.190 + * Shift value for indexing within segments.
49.191 + */
49.192 + final int segmentShift;
49.193 +
49.194 + /**
49.195 + * The segments, each of which is a specialized hash table.
49.196 + */
49.197 + final Segment<K,V>[] segments;
49.198 +
49.199 + transient Set<K> keySet;
49.200 + transient Set<Map.Entry<K,V>> entrySet;
49.201 + transient Collection<V> values;
49.202 +
49.203 + /**
49.204 + * ConcurrentHashMap list entry. Note that this is never exported
49.205 + * out as a user-visible Map.Entry.
49.206 + */
49.207 + static final class HashEntry<K,V> {
49.208 + final int hash;
49.209 + final K key;
49.210 + volatile V value;
49.211 + volatile HashEntry<K,V> next;
49.212 +
49.213 + HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
49.214 + this.hash = hash;
49.215 + this.key = key;
49.216 + this.value = value;
49.217 + this.next = next;
49.218 + }
49.219 +
49.220 + /**
49.221 + * Sets next field with volatile write semantics. (See above
49.222 + * about use of putOrderedObject.)
49.223 + */
49.224 + final void setNext(HashEntry<K,V> n) {
49.225 + UNSAFE.putOrderedObject(this, nextOffset, n);
49.226 + }
49.227 +
49.228 + // Unsafe mechanics
49.229 + static final sun.misc.Unsafe UNSAFE;
49.230 + static final long nextOffset;
49.231 + static {
49.232 + try {
49.233 + UNSAFE = sun.misc.Unsafe.getUnsafe();
49.234 + Class k = HashEntry.class;
49.235 + nextOffset = UNSAFE.objectFieldOffset
49.236 + (k.getDeclaredField("next"));
49.237 + } catch (Exception e) {
49.238 + throw new Error(e);
49.239 + }
49.240 + }
49.241 + }
49.242 +
49.243 + /**
49.244 + * Gets the ith element of given table (if nonnull) with volatile
49.245 + * read semantics. Note: This is manually integrated into a few
49.246 + * performance-sensitive methods to reduce call overhead.
49.247 + */
49.248 + @SuppressWarnings("unchecked")
49.249 + static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {
49.250 + return (tab == null) ? null :
49.251 + (HashEntry<K,V>) UNSAFE.getObjectVolatile
49.252 + (tab, ((long)i << TSHIFT) + TBASE);
49.253 + }
49.254 +
49.255 + /**
49.256 + * Sets the ith element of given table, with volatile write
49.257 + * semantics. (See above about use of putOrderedObject.)
49.258 + */
49.259 + static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
49.260 + HashEntry<K,V> e) {
49.261 + UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
49.262 + }
49.263 +
49.264 + /**
49.265 + * Applies a supplemental hash function to a given hashCode, which
49.266 + * defends against poor quality hash functions. This is critical
49.267 + * because ConcurrentHashMap uses power-of-two length hash tables,
49.268 + * that otherwise encounter collisions for hashCodes that do not
49.269 + * differ in lower or upper bits.
49.270 + */
49.271 + private static int hash(int h) {
49.272 + // Spread bits to regularize both segment and index locations,
49.273 + // using variant of single-word Wang/Jenkins hash.
49.274 + h += (h << 15) ^ 0xffffcd7d;
49.275 + h ^= (h >>> 10);
49.276 + h += (h << 3);
49.277 + h ^= (h >>> 6);
49.278 + h += (h << 2) + (h << 14);
49.279 + return h ^ (h >>> 16);
49.280 + }
49.281 +
49.282 + /**
49.283 + * Segments are specialized versions of hash tables. This
49.284 + * subclasses from ReentrantLock opportunistically, just to
49.285 + * simplify some locking and avoid separate construction.
49.286 + */
49.287 + static final class Segment<K,V> extends ReentrantLock implements Serializable {
49.288 + /*
49.289 + * Segments maintain a table of entry lists that are always
49.290 + * kept in a consistent state, so can be read (via volatile
49.291 + * reads of segments and tables) without locking. This
49.292 + * requires replicating nodes when necessary during table
49.293 + * resizing, so the old lists can be traversed by readers
49.294 + * still using old version of table.
49.295 + *
49.296 + * This class defines only mutative methods requiring locking.
49.297 + * Except as noted, the methods of this class perform the
49.298 + * per-segment versions of ConcurrentHashMap methods. (Other
49.299 + * methods are integrated directly into ConcurrentHashMap
49.300 + * methods.) These mutative methods use a form of controlled
49.301 + * spinning on contention via methods scanAndLock and
49.302 + * scanAndLockForPut. These intersperse tryLocks with
49.303 + * traversals to locate nodes. The main benefit is to absorb
49.304 + * cache misses (which are very common for hash tables) while
49.305 + * obtaining locks so that traversal is faster once
49.306 + * acquired. We do not actually use the found nodes since they
49.307 + * must be re-acquired under lock anyway to ensure sequential
49.308 + * consistency of updates (and in any case may be undetectably
49.309 + * stale), but they will normally be much faster to re-locate.
49.310 + * Also, scanAndLockForPut speculatively creates a fresh node
49.311 + * to use in put if no node is found.
49.312 + */
49.313 +
49.314 + private static final long serialVersionUID = 2249069246763182397L;
49.315 +
49.316 + /**
49.317 + * The maximum number of times to tryLock in a prescan before
49.318 + * possibly blocking on acquire in preparation for a locked
49.319 + * segment operation. On multiprocessors, using a bounded
49.320 + * number of retries maintains cache acquired while locating
49.321 + * nodes.
49.322 + */
49.323 + static final int MAX_SCAN_RETRIES =
49.324 + Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
49.325 +
49.326 + /**
49.327 + * The per-segment table. Elements are accessed via
49.328 + * entryAt/setEntryAt providing volatile semantics.
49.329 + */
49.330 + transient volatile HashEntry<K,V>[] table;
49.331 +
49.332 + /**
49.333 + * The number of elements. Accessed only either within locks
49.334 + * or among other volatile reads that maintain visibility.
49.335 + */
49.336 + transient int count;
49.337 +
49.338 + /**
49.339 + * The total number of mutative operations in this segment.
49.340 + * Even though this may overflows 32 bits, it provides
49.341 + * sufficient accuracy for stability checks in CHM isEmpty()
49.342 + * and size() methods. Accessed only either within locks or
49.343 + * among other volatile reads that maintain visibility.
49.344 + */
49.345 + transient int modCount;
49.346 +
49.347 + /**
49.348 + * The table is rehashed when its size exceeds this threshold.
49.349 + * (The value of this field is always <tt>(int)(capacity *
49.350 + * loadFactor)</tt>.)
49.351 + */
49.352 + transient int threshold;
49.353 +
49.354 + /**
49.355 + * The load factor for the hash table. Even though this value
49.356 + * is same for all segments, it is replicated to avoid needing
49.357 + * links to outer object.
49.358 + * @serial
49.359 + */
49.360 + final float loadFactor;
49.361 +
49.362 + Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
49.363 + this.loadFactor = lf;
49.364 + this.threshold = threshold;
49.365 + this.table = tab;
49.366 + }
49.367 +
49.368 + final V put(K key, int hash, V value, boolean onlyIfAbsent) {
49.369 + HashEntry<K,V> node = tryLock() ? null :
49.370 + scanAndLockForPut(key, hash, value);
49.371 + V oldValue;
49.372 + try {
49.373 + HashEntry<K,V>[] tab = table;
49.374 + int index = (tab.length - 1) & hash;
49.375 + HashEntry<K,V> first = entryAt(tab, index);
49.376 + for (HashEntry<K,V> e = first;;) {
49.377 + if (e != null) {
49.378 + K k;
49.379 + if ((k = e.key) == key ||
49.380 + (e.hash == hash && key.equals(k))) {
49.381 + oldValue = e.value;
49.382 + if (!onlyIfAbsent) {
49.383 + e.value = value;
49.384 + ++modCount;
49.385 + }
49.386 + break;
49.387 + }
49.388 + e = e.next;
49.389 + }
49.390 + else {
49.391 + if (node != null)
49.392 + node.setNext(first);
49.393 + else
49.394 + node = new HashEntry<K,V>(hash, key, value, first);
49.395 + int c = count + 1;
49.396 + if (c > threshold && tab.length < MAXIMUM_CAPACITY)
49.397 + rehash(node);
49.398 + else
49.399 + setEntryAt(tab, index, node);
49.400 + ++modCount;
49.401 + count = c;
49.402 + oldValue = null;
49.403 + break;
49.404 + }
49.405 + }
49.406 + } finally {
49.407 + unlock();
49.408 + }
49.409 + return oldValue;
49.410 + }
49.411 +
49.412 + /**
49.413 + * Doubles size of table and repacks entries, also adding the
49.414 + * given node to new table
49.415 + */
49.416 + @SuppressWarnings("unchecked")
49.417 + private void rehash(HashEntry<K,V> node) {
49.418 + /*
49.419 + * Reclassify nodes in each list to new table. Because we
49.420 + * are using power-of-two expansion, the elements from
49.421 + * each bin must either stay at same index, or move with a
49.422 + * power of two offset. We eliminate unnecessary node
49.423 + * creation by catching cases where old nodes can be
49.424 + * reused because their next fields won't change.
49.425 + * Statistically, at the default threshold, only about
49.426 + * one-sixth of them need cloning when a table
49.427 + * doubles. The nodes they replace will be garbage
49.428 + * collectable as soon as they are no longer referenced by
49.429 + * any reader thread that may be in the midst of
49.430 + * concurrently traversing table. Entry accesses use plain
49.431 + * array indexing because they are followed by volatile
49.432 + * table write.
49.433 + */
49.434 + HashEntry<K,V>[] oldTable = table;
49.435 + int oldCapacity = oldTable.length;
49.436 + int newCapacity = oldCapacity << 1;
49.437 + threshold = (int)(newCapacity * loadFactor);
49.438 + HashEntry<K,V>[] newTable =
49.439 + (HashEntry<K,V>[]) new HashEntry[newCapacity];
49.440 + int sizeMask = newCapacity - 1;
49.441 + for (int i = 0; i < oldCapacity ; i++) {
49.442 + HashEntry<K,V> e = oldTable[i];
49.443 + if (e != null) {
49.444 + HashEntry<K,V> next = e.next;
49.445 + int idx = e.hash & sizeMask;
49.446 + if (next == null) // Single node on list
49.447 + newTable[idx] = e;
49.448 + else { // Reuse consecutive sequence at same slot
49.449 + HashEntry<K,V> lastRun = e;
49.450 + int lastIdx = idx;
49.451 + for (HashEntry<K,V> last = next;
49.452 + last != null;
49.453 + last = last.next) {
49.454 + int k = last.hash & sizeMask;
49.455 + if (k != lastIdx) {
49.456 + lastIdx = k;
49.457 + lastRun = last;
49.458 + }
49.459 + }
49.460 + newTable[lastIdx] = lastRun;
49.461 + // Clone remaining nodes
49.462 + for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
49.463 + V v = p.value;
49.464 + int h = p.hash;
49.465 + int k = h & sizeMask;
49.466 + HashEntry<K,V> n = newTable[k];
49.467 + newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
49.468 + }
49.469 + }
49.470 + }
49.471 + }
49.472 + int nodeIndex = node.hash & sizeMask; // add the new node
49.473 + node.setNext(newTable[nodeIndex]);
49.474 + newTable[nodeIndex] = node;
49.475 + table = newTable;
49.476 + }
49.477 +
49.478 + /**
49.479 + * Scans for a node containing given key while trying to
49.480 + * acquire lock, creating and returning one if not found. Upon
49.481 + * return, guarantees that lock is held. UNlike in most
49.482 + * methods, calls to method equals are not screened: Since
49.483 + * traversal speed doesn't matter, we might as well help warm
49.484 + * up the associated code and accesses as well.
49.485 + *
49.486 + * @return a new node if key not found, else null
49.487 + */
49.488 + private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
49.489 + HashEntry<K,V> first = entryForHash(this, hash);
49.490 + HashEntry<K,V> e = first;
49.491 + HashEntry<K,V> node = null;
49.492 + int retries = -1; // negative while locating node
49.493 + while (!tryLock()) {
49.494 + HashEntry<K,V> f; // to recheck first below
49.495 + if (retries < 0) {
49.496 + if (e == null) {
49.497 + if (node == null) // speculatively create node
49.498 + node = new HashEntry<K,V>(hash, key, value, null);
49.499 + retries = 0;
49.500 + }
49.501 + else if (key.equals(e.key))
49.502 + retries = 0;
49.503 + else
49.504 + e = e.next;
49.505 + }
49.506 + else if (++retries > MAX_SCAN_RETRIES) {
49.507 + lock();
49.508 + break;
49.509 + }
49.510 + else if ((retries & 1) == 0 &&
49.511 + (f = entryForHash(this, hash)) != first) {
49.512 + e = first = f; // re-traverse if entry changed
49.513 + retries = -1;
49.514 + }
49.515 + }
49.516 + return node;
49.517 + }
49.518 +
49.519 + /**
49.520 + * Scans for a node containing the given key while trying to
49.521 + * acquire lock for a remove or replace operation. Upon
49.522 + * return, guarantees that lock is held. Note that we must
49.523 + * lock even if the key is not found, to ensure sequential
49.524 + * consistency of updates.
49.525 + */
49.526 + private void scanAndLock(Object key, int hash) {
49.527 + // similar to but simpler than scanAndLockForPut
49.528 + HashEntry<K,V> first = entryForHash(this, hash);
49.529 + HashEntry<K,V> e = first;
49.530 + int retries = -1;
49.531 + while (!tryLock()) {
49.532 + HashEntry<K,V> f;
49.533 + if (retries < 0) {
49.534 + if (e == null || key.equals(e.key))
49.535 + retries = 0;
49.536 + else
49.537 + e = e.next;
49.538 + }
49.539 + else if (++retries > MAX_SCAN_RETRIES) {
49.540 + lock();
49.541 + break;
49.542 + }
49.543 + else if ((retries & 1) == 0 &&
49.544 + (f = entryForHash(this, hash)) != first) {
49.545 + e = first = f;
49.546 + retries = -1;
49.547 + }
49.548 + }
49.549 + }
49.550 +
49.551 + /**
49.552 + * Remove; match on key only if value null, else match both.
49.553 + */
49.554 + final V remove(Object key, int hash, Object value) {
49.555 + if (!tryLock())
49.556 + scanAndLock(key, hash);
49.557 + V oldValue = null;
49.558 + try {
49.559 + HashEntry<K,V>[] tab = table;
49.560 + int index = (tab.length - 1) & hash;
49.561 + HashEntry<K,V> e = entryAt(tab, index);
49.562 + HashEntry<K,V> pred = null;
49.563 + while (e != null) {
49.564 + K k;
49.565 + HashEntry<K,V> next = e.next;
49.566 + if ((k = e.key) == key ||
49.567 + (e.hash == hash && key.equals(k))) {
49.568 + V v = e.value;
49.569 + if (value == null || value == v || value.equals(v)) {
49.570 + if (pred == null)
49.571 + setEntryAt(tab, index, next);
49.572 + else
49.573 + pred.setNext(next);
49.574 + ++modCount;
49.575 + --count;
49.576 + oldValue = v;
49.577 + }
49.578 + break;
49.579 + }
49.580 + pred = e;
49.581 + e = next;
49.582 + }
49.583 + } finally {
49.584 + unlock();
49.585 + }
49.586 + return oldValue;
49.587 + }
49.588 +
49.589 + final boolean replace(K key, int hash, V oldValue, V newValue) {
49.590 + if (!tryLock())
49.591 + scanAndLock(key, hash);
49.592 + boolean replaced = false;
49.593 + try {
49.594 + HashEntry<K,V> e;
49.595 + for (e = entryForHash(this, hash); e != null; e = e.next) {
49.596 + K k;
49.597 + if ((k = e.key) == key ||
49.598 + (e.hash == hash && key.equals(k))) {
49.599 + if (oldValue.equals(e.value)) {
49.600 + e.value = newValue;
49.601 + ++modCount;
49.602 + replaced = true;
49.603 + }
49.604 + break;
49.605 + }
49.606 + }
49.607 + } finally {
49.608 + unlock();
49.609 + }
49.610 + return replaced;
49.611 + }
49.612 +
49.613 + final V replace(K key, int hash, V value) {
49.614 + if (!tryLock())
49.615 + scanAndLock(key, hash);
49.616 + V oldValue = null;
49.617 + try {
49.618 + HashEntry<K,V> e;
49.619 + for (e = entryForHash(this, hash); e != null; e = e.next) {
49.620 + K k;
49.621 + if ((k = e.key) == key ||
49.622 + (e.hash == hash && key.equals(k))) {
49.623 + oldValue = e.value;
49.624 + e.value = value;
49.625 + ++modCount;
49.626 + break;
49.627 + }
49.628 + }
49.629 + } finally {
49.630 + unlock();
49.631 + }
49.632 + return oldValue;
49.633 + }
49.634 +
49.635 + final void clear() {
49.636 + lock();
49.637 + try {
49.638 + HashEntry<K,V>[] tab = table;
49.639 + for (int i = 0; i < tab.length ; i++)
49.640 + setEntryAt(tab, i, null);
49.641 + ++modCount;
49.642 + count = 0;
49.643 + } finally {
49.644 + unlock();
49.645 + }
49.646 + }
49.647 + }
49.648 +
49.649 + // Accessing segments
49.650 +
49.651 + /**
49.652 + * Gets the jth element of given segment array (if nonnull) with
49.653 + * volatile element access semantics via Unsafe. (The null check
49.654 + * can trigger harmlessly only during deserialization.) Note:
49.655 + * because each element of segments array is set only once (using
49.656 + * fully ordered writes), some performance-sensitive methods rely
49.657 + * on this method only as a recheck upon null reads.
49.658 + */
49.659 + @SuppressWarnings("unchecked")
49.660 + static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {
49.661 + long u = (j << SSHIFT) + SBASE;
49.662 + return ss == null ? null :
49.663 + (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);
49.664 + }
49.665 +
49.666 + /**
49.667 + * Returns the segment for the given index, creating it and
49.668 + * recording in segment table (via CAS) if not already present.
49.669 + *
49.670 + * @param k the index
49.671 + * @return the segment
49.672 + */
49.673 + @SuppressWarnings("unchecked")
49.674 + private Segment<K,V> ensureSegment(int k) {
49.675 + final Segment<K,V>[] ss = this.segments;
49.676 + long u = (k << SSHIFT) + SBASE; // raw offset
49.677 + Segment<K,V> seg;
49.678 + if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
49.679 + Segment<K,V> proto = ss[0]; // use segment 0 as prototype
49.680 + int cap = proto.table.length;
49.681 + float lf = proto.loadFactor;
49.682 + int threshold = (int)(cap * lf);
49.683 + HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
49.684 + if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
49.685 + == null) { // recheck
49.686 + Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
49.687 + while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
49.688 + == null) {
49.689 + if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
49.690 + break;
49.691 + }
49.692 + }
49.693 + }
49.694 + return seg;
49.695 + }
49.696 +
49.697 + // Hash-based segment and entry accesses
49.698 +
49.699 + /**
49.700 + * Get the segment for the given hash
49.701 + */
49.702 + @SuppressWarnings("unchecked")
49.703 + private Segment<K,V> segmentForHash(int h) {
49.704 + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
49.705 + return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u);
49.706 + }
49.707 +
49.708 + /**
49.709 + * Gets the table entry for the given segment and hash
49.710 + */
49.711 + @SuppressWarnings("unchecked")
49.712 + static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {
49.713 + HashEntry<K,V>[] tab;
49.714 + return (seg == null || (tab = seg.table) == null) ? null :
49.715 + (HashEntry<K,V>) UNSAFE.getObjectVolatile
49.716 + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
49.717 + }
49.718 +
49.719 + /* ---------------- Public operations -------------- */
49.720 +
49.721 + /**
49.722 + * Creates a new, empty map with the specified initial
49.723 + * capacity, load factor and concurrency level.
49.724 + *
49.725 + * @param initialCapacity the initial capacity. The implementation
49.726 + * performs internal sizing to accommodate this many elements.
49.727 + * @param loadFactor the load factor threshold, used to control resizing.
49.728 + * Resizing may be performed when the average number of elements per
49.729 + * bin exceeds this threshold.
49.730 + * @param concurrencyLevel the estimated number of concurrently
49.731 + * updating threads. The implementation performs internal sizing
49.732 + * to try to accommodate this many threads.
49.733 + * @throws IllegalArgumentException if the initial capacity is
49.734 + * negative or the load factor or concurrencyLevel are
49.735 + * nonpositive.
49.736 + */
49.737 + @SuppressWarnings("unchecked")
49.738 + public ConcurrentHashMap(int initialCapacity,
49.739 + float loadFactor, int concurrencyLevel) {
49.740 + if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
49.741 + throw new IllegalArgumentException();
49.742 + if (concurrencyLevel > MAX_SEGMENTS)
49.743 + concurrencyLevel = MAX_SEGMENTS;
49.744 + // Find power-of-two sizes best matching arguments
49.745 + int sshift = 0;
49.746 + int ssize = 1;
49.747 + while (ssize < concurrencyLevel) {
49.748 + ++sshift;
49.749 + ssize <<= 1;
49.750 + }
49.751 + this.segmentShift = 32 - sshift;
49.752 + this.segmentMask = ssize - 1;
49.753 + if (initialCapacity > MAXIMUM_CAPACITY)
49.754 + initialCapacity = MAXIMUM_CAPACITY;
49.755 + int c = initialCapacity / ssize;
49.756 + if (c * ssize < initialCapacity)
49.757 + ++c;
49.758 + int cap = MIN_SEGMENT_TABLE_CAPACITY;
49.759 + while (cap < c)
49.760 + cap <<= 1;
49.761 + // create segments and segments[0]
49.762 + Segment<K,V> s0 =
49.763 + new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
49.764 + (HashEntry<K,V>[])new HashEntry[cap]);
49.765 + Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
49.766 + UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
49.767 + this.segments = ss;
49.768 + }
49.769 +
49.770 + /**
49.771 + * Creates a new, empty map with the specified initial capacity
49.772 + * and load factor and with the default concurrencyLevel (16).
49.773 + *
49.774 + * @param initialCapacity The implementation performs internal
49.775 + * sizing to accommodate this many elements.
49.776 + * @param loadFactor the load factor threshold, used to control resizing.
49.777 + * Resizing may be performed when the average number of elements per
49.778 + * bin exceeds this threshold.
49.779 + * @throws IllegalArgumentException if the initial capacity of
49.780 + * elements is negative or the load factor is nonpositive
49.781 + *
49.782 + * @since 1.6
49.783 + */
49.784 + public ConcurrentHashMap(int initialCapacity, float loadFactor) {
49.785 + this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
49.786 + }
49.787 +
49.788 + /**
49.789 + * Creates a new, empty map with the specified initial capacity,
49.790 + * and with default load factor (0.75) and concurrencyLevel (16).
49.791 + *
49.792 + * @param initialCapacity the initial capacity. The implementation
49.793 + * performs internal sizing to accommodate this many elements.
49.794 + * @throws IllegalArgumentException if the initial capacity of
49.795 + * elements is negative.
49.796 + */
49.797 + public ConcurrentHashMap(int initialCapacity) {
49.798 + this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
49.799 + }
49.800 +
49.801 + /**
49.802 + * Creates a new, empty map with a default initial capacity (16),
49.803 + * load factor (0.75) and concurrencyLevel (16).
49.804 + */
49.805 + public ConcurrentHashMap() {
49.806 + this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
49.807 + }
49.808 +
49.809 + /**
49.810 + * Creates a new map with the same mappings as the given map.
49.811 + * The map is created with a capacity of 1.5 times the number
49.812 + * of mappings in the given map or 16 (whichever is greater),
49.813 + * and a default load factor (0.75) and concurrencyLevel (16).
49.814 + *
49.815 + * @param m the map
49.816 + */
49.817 + public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
49.818 + this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
49.819 + DEFAULT_INITIAL_CAPACITY),
49.820 + DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
49.821 + putAll(m);
49.822 + }
49.823 +
49.824 + /**
49.825 + * Returns <tt>true</tt> if this map contains no key-value mappings.
49.826 + *
49.827 + * @return <tt>true</tt> if this map contains no key-value mappings
49.828 + */
49.829 + public boolean isEmpty() {
49.830 + /*
49.831 + * Sum per-segment modCounts to avoid mis-reporting when
49.832 + * elements are concurrently added and removed in one segment
49.833 + * while checking another, in which case the table was never
49.834 + * actually empty at any point. (The sum ensures accuracy up
49.835 + * through at least 1<<31 per-segment modifications before
49.836 + * recheck.) Methods size() and containsValue() use similar
49.837 + * constructions for stability checks.
49.838 + */
49.839 + long sum = 0L;
49.840 + final Segment<K,V>[] segments = this.segments;
49.841 + for (int j = 0; j < segments.length; ++j) {
49.842 + Segment<K,V> seg = segmentAt(segments, j);
49.843 + if (seg != null) {
49.844 + if (seg.count != 0)
49.845 + return false;
49.846 + sum += seg.modCount;
49.847 + }
49.848 + }
49.849 + if (sum != 0L) { // recheck unless no modifications
49.850 + for (int j = 0; j < segments.length; ++j) {
49.851 + Segment<K,V> seg = segmentAt(segments, j);
49.852 + if (seg != null) {
49.853 + if (seg.count != 0)
49.854 + return false;
49.855 + sum -= seg.modCount;
49.856 + }
49.857 + }
49.858 + if (sum != 0L)
49.859 + return false;
49.860 + }
49.861 + return true;
49.862 + }
49.863 +
49.864 + /**
49.865 + * Returns the number of key-value mappings in this map. If the
49.866 + * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
49.867 + * <tt>Integer.MAX_VALUE</tt>.
49.868 + *
49.869 + * @return the number of key-value mappings in this map
49.870 + */
49.871 + public int size() {
49.872 + // Try a few times to get accurate count. On failure due to
49.873 + // continuous async changes in table, resort to locking.
49.874 + final Segment<K,V>[] segments = this.segments;
49.875 + int size;
49.876 + boolean overflow; // true if size overflows 32 bits
49.877 + long sum; // sum of modCounts
49.878 + long last = 0L; // previous sum
49.879 + int retries = -1; // first iteration isn't retry
49.880 + try {
49.881 + for (;;) {
49.882 + if (retries++ == RETRIES_BEFORE_LOCK) {
49.883 + for (int j = 0; j < segments.length; ++j)
49.884 + ensureSegment(j).lock(); // force creation
49.885 + }
49.886 + sum = 0L;
49.887 + size = 0;
49.888 + overflow = false;
49.889 + for (int j = 0; j < segments.length; ++j) {
49.890 + Segment<K,V> seg = segmentAt(segments, j);
49.891 + if (seg != null) {
49.892 + sum += seg.modCount;
49.893 + int c = seg.count;
49.894 + if (c < 0 || (size += c) < 0)
49.895 + overflow = true;
49.896 + }
49.897 + }
49.898 + if (sum == last)
49.899 + break;
49.900 + last = sum;
49.901 + }
49.902 + } finally {
49.903 + if (retries > RETRIES_BEFORE_LOCK) {
49.904 + for (int j = 0; j < segments.length; ++j)
49.905 + segmentAt(segments, j).unlock();
49.906 + }
49.907 + }
49.908 + return overflow ? Integer.MAX_VALUE : size;
49.909 + }
49.910 +
49.911 + /**
49.912 + * Returns the value to which the specified key is mapped,
49.913 + * or {@code null} if this map contains no mapping for the key.
49.914 + *
49.915 + * <p>More formally, if this map contains a mapping from a key
49.916 + * {@code k} to a value {@code v} such that {@code key.equals(k)},
49.917 + * then this method returns {@code v}; otherwise it returns
49.918 + * {@code null}. (There can be at most one such mapping.)
49.919 + *
49.920 + * @throws NullPointerException if the specified key is null
49.921 + */
49.922 + public V get(Object key) {
49.923 + Segment<K,V> s; // manually integrate access methods to reduce overhead
49.924 + HashEntry<K,V>[] tab;
49.925 + int h = hash(key.hashCode());
49.926 + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
49.927 + if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
49.928 + (tab = s.table) != null) {
49.929 + for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
49.930 + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
49.931 + e != null; e = e.next) {
49.932 + K k;
49.933 + if ((k = e.key) == key || (e.hash == h && key.equals(k)))
49.934 + return e.value;
49.935 + }
49.936 + }
49.937 + return null;
49.938 + }
49.939 +
49.940 + /**
49.941 + * Tests if the specified object is a key in this table.
49.942 + *
49.943 + * @param key possible key
49.944 + * @return <tt>true</tt> if and only if the specified object
49.945 + * is a key in this table, as determined by the
49.946 + * <tt>equals</tt> method; <tt>false</tt> otherwise.
49.947 + * @throws NullPointerException if the specified key is null
49.948 + */
49.949 + @SuppressWarnings("unchecked")
49.950 + public boolean containsKey(Object key) {
49.951 + Segment<K,V> s; // same as get() except no need for volatile value read
49.952 + HashEntry<K,V>[] tab;
49.953 + int h = hash(key.hashCode());
49.954 + long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
49.955 + if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
49.956 + (tab = s.table) != null) {
49.957 + for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
49.958 + (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
49.959 + e != null; e = e.next) {
49.960 + K k;
49.961 + if ((k = e.key) == key || (e.hash == h && key.equals(k)))
49.962 + return true;
49.963 + }
49.964 + }
49.965 + return false;
49.966 + }
49.967 +
49.968 + /**
49.969 + * Returns <tt>true</tt> if this map maps one or more keys to the
49.970 + * specified value. Note: This method requires a full internal
49.971 + * traversal of the hash table, and so is much slower than
49.972 + * method <tt>containsKey</tt>.
49.973 + *
49.974 + * @param value value whose presence in this map is to be tested
49.975 + * @return <tt>true</tt> if this map maps one or more keys to the
49.976 + * specified value
49.977 + * @throws NullPointerException if the specified value is null
49.978 + */
49.979 + public boolean containsValue(Object value) {
49.980 + // Same idea as size()
49.981 + if (value == null)
49.982 + throw new NullPointerException();
49.983 + final Segment<K,V>[] segments = this.segments;
49.984 + boolean found = false;
49.985 + long last = 0;
49.986 + int retries = -1;
49.987 + try {
49.988 + outer: for (;;) {
49.989 + if (retries++ == RETRIES_BEFORE_LOCK) {
49.990 + for (int j = 0; j < segments.length; ++j)
49.991 + ensureSegment(j).lock(); // force creation
49.992 + }
49.993 + long hashSum = 0L;
49.994 + int sum = 0;
49.995 + for (int j = 0; j < segments.length; ++j) {
49.996 + HashEntry<K,V>[] tab;
49.997 + Segment<K,V> seg = segmentAt(segments, j);
49.998 + if (seg != null && (tab = seg.table) != null) {
49.999 + for (int i = 0 ; i < tab.length; i++) {
49.1000 + HashEntry<K,V> e;
49.1001 + for (e = entryAt(tab, i); e != null; e = e.next) {
49.1002 + V v = e.value;
49.1003 + if (v != null && value.equals(v)) {
49.1004 + found = true;
49.1005 + break outer;
49.1006 + }
49.1007 + }
49.1008 + }
49.1009 + sum += seg.modCount;
49.1010 + }
49.1011 + }
49.1012 + if (retries > 0 && sum == last)
49.1013 + break;
49.1014 + last = sum;
49.1015 + }
49.1016 + } finally {
49.1017 + if (retries > RETRIES_BEFORE_LOCK) {
49.1018 + for (int j = 0; j < segments.length; ++j)
49.1019 + segmentAt(segments, j).unlock();
49.1020 + }
49.1021 + }
49.1022 + return found;
49.1023 + }
49.1024 +
49.1025 + /**
49.1026 + * Legacy method testing if some key maps into the specified value
49.1027 + * in this table. This method is identical in functionality to
49.1028 + * {@link #containsValue}, and exists solely to ensure
49.1029 + * full compatibility with class {@link java.util.Hashtable},
49.1030 + * which supported this method prior to introduction of the
49.1031 + * Java Collections framework.
49.1032 +
49.1033 + * @param value a value to search for
49.1034 + * @return <tt>true</tt> if and only if some key maps to the
49.1035 + * <tt>value</tt> argument in this table as
49.1036 + * determined by the <tt>equals</tt> method;
49.1037 + * <tt>false</tt> otherwise
49.1038 + * @throws NullPointerException if the specified value is null
49.1039 + */
49.1040 + public boolean contains(Object value) {
49.1041 + return containsValue(value);
49.1042 + }
49.1043 +
49.1044 + /**
49.1045 + * Maps the specified key to the specified value in this table.
49.1046 + * Neither the key nor the value can be null.
49.1047 + *
49.1048 + * <p> The value can be retrieved by calling the <tt>get</tt> method
49.1049 + * with a key that is equal to the original key.
49.1050 + *
49.1051 + * @param key key with which the specified value is to be associated
49.1052 + * @param value value to be associated with the specified key
49.1053 + * @return the previous value associated with <tt>key</tt>, or
49.1054 + * <tt>null</tt> if there was no mapping for <tt>key</tt>
49.1055 + * @throws NullPointerException if the specified key or value is null
49.1056 + */
49.1057 + @SuppressWarnings("unchecked")
49.1058 + public V put(K key, V value) {
49.1059 + Segment<K,V> s;
49.1060 + if (value == null)
49.1061 + throw new NullPointerException();
49.1062 + int hash = hash(key.hashCode());
49.1063 + int j = (hash >>> segmentShift) & segmentMask;
49.1064 + if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
49.1065 + (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
49.1066 + s = ensureSegment(j);
49.1067 + return s.put(key, hash, value, false);
49.1068 + }
49.1069 +
49.1070 + /**
49.1071 + * {@inheritDoc}
49.1072 + *
49.1073 + * @return the previous value associated with the specified key,
49.1074 + * or <tt>null</tt> if there was no mapping for the key
49.1075 + * @throws NullPointerException if the specified key or value is null
49.1076 + */
49.1077 + @SuppressWarnings("unchecked")
49.1078 + public V putIfAbsent(K key, V value) {
49.1079 + Segment<K,V> s;
49.1080 + if (value == null)
49.1081 + throw new NullPointerException();
49.1082 + int hash = hash(key.hashCode());
49.1083 + int j = (hash >>> segmentShift) & segmentMask;
49.1084 + if ((s = (Segment<K,V>)UNSAFE.getObject
49.1085 + (segments, (j << SSHIFT) + SBASE)) == null)
49.1086 + s = ensureSegment(j);
49.1087 + return s.put(key, hash, value, true);
49.1088 + }
49.1089 +
49.1090 + /**
49.1091 + * Copies all of the mappings from the specified map to this one.
49.1092 + * These mappings replace any mappings that this map had for any of the
49.1093 + * keys currently in the specified map.
49.1094 + *
49.1095 + * @param m mappings to be stored in this map
49.1096 + */
49.1097 + public void putAll(Map<? extends K, ? extends V> m) {
49.1098 + for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
49.1099 + put(e.getKey(), e.getValue());
49.1100 + }
49.1101 +
49.1102 + /**
49.1103 + * Removes the key (and its corresponding value) from this map.
49.1104 + * This method does nothing if the key is not in the map.
49.1105 + *
49.1106 + * @param key the key that needs to be removed
49.1107 + * @return the previous value associated with <tt>key</tt>, or
49.1108 + * <tt>null</tt> if there was no mapping for <tt>key</tt>
49.1109 + * @throws NullPointerException if the specified key is null
49.1110 + */
49.1111 + public V remove(Object key) {
49.1112 + int hash = hash(key.hashCode());
49.1113 + Segment<K,V> s = segmentForHash(hash);
49.1114 + return s == null ? null : s.remove(key, hash, null);
49.1115 + }
49.1116 +
49.1117 + /**
49.1118 + * {@inheritDoc}
49.1119 + *
49.1120 + * @throws NullPointerException if the specified key is null
49.1121 + */
49.1122 + public boolean remove(Object key, Object value) {
49.1123 + int hash = hash(key.hashCode());
49.1124 + Segment<K,V> s;
49.1125 + return value != null && (s = segmentForHash(hash)) != null &&
49.1126 + s.remove(key, hash, value) != null;
49.1127 + }
49.1128 +
49.1129 + /**
49.1130 + * {@inheritDoc}
49.1131 + *
49.1132 + * @throws NullPointerException if any of the arguments are null
49.1133 + */
49.1134 + public boolean replace(K key, V oldValue, V newValue) {
49.1135 + int hash = hash(key.hashCode());
49.1136 + if (oldValue == null || newValue == null)
49.1137 + throw new NullPointerException();
49.1138 + Segment<K,V> s = segmentForHash(hash);
49.1139 + return s != null && s.replace(key, hash, oldValue, newValue);
49.1140 + }
49.1141 +
49.1142 + /**
49.1143 + * {@inheritDoc}
49.1144 + *
49.1145 + * @return the previous value associated with the specified key,
49.1146 + * or <tt>null</tt> if there was no mapping for the key
49.1147 + * @throws NullPointerException if the specified key or value is null
49.1148 + */
49.1149 + public V replace(K key, V value) {
49.1150 + int hash = hash(key.hashCode());
49.1151 + if (value == null)
49.1152 + throw new NullPointerException();
49.1153 + Segment<K,V> s = segmentForHash(hash);
49.1154 + return s == null ? null : s.replace(key, hash, value);
49.1155 + }
49.1156 +
49.1157 + /**
49.1158 + * Removes all of the mappings from this map.
49.1159 + */
49.1160 + public void clear() {
49.1161 + final Segment<K,V>[] segments = this.segments;
49.1162 + for (int j = 0; j < segments.length; ++j) {
49.1163 + Segment<K,V> s = segmentAt(segments, j);
49.1164 + if (s != null)
49.1165 + s.clear();
49.1166 + }
49.1167 + }
49.1168 +
49.1169 + /**
49.1170 + * Returns a {@link Set} view of the keys contained in this map.
49.1171 + * The set is backed by the map, so changes to the map are
49.1172 + * reflected in the set, and vice-versa. The set supports element
49.1173 + * removal, which removes the corresponding mapping from this map,
49.1174 + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
49.1175 + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
49.1176 + * operations. It does not support the <tt>add</tt> or
49.1177 + * <tt>addAll</tt> operations.
49.1178 + *
49.1179 + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
49.1180 + * that will never throw {@link ConcurrentModificationException},
49.1181 + * and guarantees to traverse elements as they existed upon
49.1182 + * construction of the iterator, and may (but is not guaranteed to)
49.1183 + * reflect any modifications subsequent to construction.
49.1184 + */
49.1185 + public Set<K> keySet() {
49.1186 + Set<K> ks = keySet;
49.1187 + return (ks != null) ? ks : (keySet = new KeySet());
49.1188 + }
49.1189 +
49.1190 + /**
49.1191 + * Returns a {@link Collection} view of the values contained in this map.
49.1192 + * The collection is backed by the map, so changes to the map are
49.1193 + * reflected in the collection, and vice-versa. The collection
49.1194 + * supports element removal, which removes the corresponding
49.1195 + * mapping from this map, via the <tt>Iterator.remove</tt>,
49.1196 + * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
49.1197 + * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not
49.1198 + * support the <tt>add</tt> or <tt>addAll</tt> operations.
49.1199 + *
49.1200 + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
49.1201 + * that will never throw {@link ConcurrentModificationException},
49.1202 + * and guarantees to traverse elements as they existed upon
49.1203 + * construction of the iterator, and may (but is not guaranteed to)
49.1204 + * reflect any modifications subsequent to construction.
49.1205 + */
49.1206 + public Collection<V> values() {
49.1207 + Collection<V> vs = values;
49.1208 + return (vs != null) ? vs : (values = new Values());
49.1209 + }
49.1210 +
49.1211 + /**
49.1212 + * Returns a {@link Set} view of the mappings contained in this map.
49.1213 + * The set is backed by the map, so changes to the map are
49.1214 + * reflected in the set, and vice-versa. The set supports element
49.1215 + * removal, which removes the corresponding mapping from the map,
49.1216 + * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
49.1217 + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
49.1218 + * operations. It does not support the <tt>add</tt> or
49.1219 + * <tt>addAll</tt> operations.
49.1220 + *
49.1221 + * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
49.1222 + * that will never throw {@link ConcurrentModificationException},
49.1223 + * and guarantees to traverse elements as they existed upon
49.1224 + * construction of the iterator, and may (but is not guaranteed to)
49.1225 + * reflect any modifications subsequent to construction.
49.1226 + */
49.1227 + public Set<Map.Entry<K,V>> entrySet() {
49.1228 + Set<Map.Entry<K,V>> es = entrySet;
49.1229 + return (es != null) ? es : (entrySet = new EntrySet());
49.1230 + }
49.1231 +
49.1232 + /**
49.1233 + * Returns an enumeration of the keys in this table.
49.1234 + *
49.1235 + * @return an enumeration of the keys in this table
49.1236 + * @see #keySet()
49.1237 + */
49.1238 + public Enumeration<K> keys() {
49.1239 + return new KeyIterator();
49.1240 + }
49.1241 +
49.1242 + /**
49.1243 + * Returns an enumeration of the values in this table.
49.1244 + *
49.1245 + * @return an enumeration of the values in this table
49.1246 + * @see #values()
49.1247 + */
49.1248 + public Enumeration<V> elements() {
49.1249 + return new ValueIterator();
49.1250 + }
49.1251 +
49.1252 + /* ---------------- Iterator Support -------------- */
49.1253 +
49.1254 + abstract class HashIterator {
49.1255 + int nextSegmentIndex;
49.1256 + int nextTableIndex;
49.1257 + HashEntry<K,V>[] currentTable;
49.1258 + HashEntry<K, V> nextEntry;
49.1259 + HashEntry<K, V> lastReturned;
49.1260 +
49.1261 + HashIterator() {
49.1262 + nextSegmentIndex = segments.length - 1;
49.1263 + nextTableIndex = -1;
49.1264 + advance();
49.1265 + }
49.1266 +
49.1267 + /**
49.1268 + * Set nextEntry to first node of next non-empty table
49.1269 + * (in backwards order, to simplify checks).
49.1270 + */
49.1271 + final void advance() {
49.1272 + for (;;) {
49.1273 + if (nextTableIndex >= 0) {
49.1274 + if ((nextEntry = entryAt(currentTable,
49.1275 + nextTableIndex--)) != null)
49.1276 + break;
49.1277 + }
49.1278 + else if (nextSegmentIndex >= 0) {
49.1279 + Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);
49.1280 + if (seg != null && (currentTable = seg.table) != null)
49.1281 + nextTableIndex = currentTable.length - 1;
49.1282 + }
49.1283 + else
49.1284 + break;
49.1285 + }
49.1286 + }
49.1287 +
49.1288 + final HashEntry<K,V> nextEntry() {
49.1289 + HashEntry<K,V> e = nextEntry;
49.1290 + if (e == null)
49.1291 + throw new NoSuchElementException();
49.1292 + lastReturned = e; // cannot assign until after null check
49.1293 + if ((nextEntry = e.next) == null)
49.1294 + advance();
49.1295 + return e;
49.1296 + }
49.1297 +
49.1298 + public final boolean hasNext() { return nextEntry != null; }
49.1299 + public final boolean hasMoreElements() { return nextEntry != null; }
49.1300 +
49.1301 + public final void remove() {
49.1302 + if (lastReturned == null)
49.1303 + throw new IllegalStateException();
49.1304 + ConcurrentHashMap.this.remove(lastReturned.key);
49.1305 + lastReturned = null;
49.1306 + }
49.1307 + }
49.1308 +
49.1309 + final class KeyIterator
49.1310 + extends HashIterator
49.1311 + implements Iterator<K>, Enumeration<K>
49.1312 + {
49.1313 + public final K next() { return super.nextEntry().key; }
49.1314 + public final K nextElement() { return super.nextEntry().key; }
49.1315 + }
49.1316 +
49.1317 + final class ValueIterator
49.1318 + extends HashIterator
49.1319 + implements Iterator<V>, Enumeration<V>
49.1320 + {
49.1321 + public final V next() { return super.nextEntry().value; }
49.1322 + public final V nextElement() { return super.nextEntry().value; }
49.1323 + }
49.1324 +
49.1325 + /**
49.1326 + * Custom Entry class used by EntryIterator.next(), that relays
49.1327 + * setValue changes to the underlying map.
49.1328 + */
49.1329 + final class WriteThroughEntry
49.1330 + extends AbstractMap.SimpleEntry<K,V>
49.1331 + {
49.1332 + WriteThroughEntry(K k, V v) {
49.1333 + super(k,v);
49.1334 + }
49.1335 +
49.1336 + /**
49.1337 + * Set our entry's value and write through to the map. The
49.1338 + * value to return is somewhat arbitrary here. Since a
49.1339 + * WriteThroughEntry does not necessarily track asynchronous
49.1340 + * changes, the most recent "previous" value could be
49.1341 + * different from what we return (or could even have been
49.1342 + * removed in which case the put will re-establish). We do not
49.1343 + * and cannot guarantee more.
49.1344 + */
49.1345 + public V setValue(V value) {
49.1346 + if (value == null) throw new NullPointerException();
49.1347 + V v = super.setValue(value);
49.1348 + ConcurrentHashMap.this.put(getKey(), value);
49.1349 + return v;
49.1350 + }
49.1351 + }
49.1352 +
49.1353 + final class EntryIterator
49.1354 + extends HashIterator
49.1355 + implements Iterator<Entry<K,V>>
49.1356 + {
49.1357 + public Map.Entry<K,V> next() {
49.1358 + HashEntry<K,V> e = super.nextEntry();
49.1359 + return new WriteThroughEntry(e.key, e.value);
49.1360 + }
49.1361 + }
49.1362 +
49.1363 + final class KeySet extends AbstractSet<K> {
49.1364 + public Iterator<K> iterator() {
49.1365 + return new KeyIterator();
49.1366 + }
49.1367 + public int size() {
49.1368 + return ConcurrentHashMap.this.size();
49.1369 + }
49.1370 + public boolean isEmpty() {
49.1371 + return ConcurrentHashMap.this.isEmpty();
49.1372 + }
49.1373 + public boolean contains(Object o) {
49.1374 + return ConcurrentHashMap.this.containsKey(o);
49.1375 + }
49.1376 + public boolean remove(Object o) {
49.1377 + return ConcurrentHashMap.this.remove(o) != null;
49.1378 + }
49.1379 + public void clear() {
49.1380 + ConcurrentHashMap.this.clear();
49.1381 + }
49.1382 + }
49.1383 +
49.1384 + final class Values extends AbstractCollection<V> {
49.1385 + public Iterator<V> iterator() {
49.1386 + return new ValueIterator();
49.1387 + }
49.1388 + public int size() {
49.1389 + return ConcurrentHashMap.this.size();
49.1390 + }
49.1391 + public boolean isEmpty() {
49.1392 + return ConcurrentHashMap.this.isEmpty();
49.1393 + }
49.1394 + public boolean contains(Object o) {
49.1395 + return ConcurrentHashMap.this.containsValue(o);
49.1396 + }
49.1397 + public void clear() {
49.1398 + ConcurrentHashMap.this.clear();
49.1399 + }
49.1400 + }
49.1401 +
49.1402 + final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
49.1403 + public Iterator<Map.Entry<K,V>> iterator() {
49.1404 + return new EntryIterator();
49.1405 + }
49.1406 + public boolean contains(Object o) {
49.1407 + if (!(o instanceof Map.Entry))
49.1408 + return false;
49.1409 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
49.1410 + V v = ConcurrentHashMap.this.get(e.getKey());
49.1411 + return v != null && v.equals(e.getValue());
49.1412 + }
49.1413 + public boolean remove(Object o) {
49.1414 + if (!(o instanceof Map.Entry))
49.1415 + return false;
49.1416 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
49.1417 + return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
49.1418 + }
49.1419 + public int size() {
49.1420 + return ConcurrentHashMap.this.size();
49.1421 + }
49.1422 + public boolean isEmpty() {
49.1423 + return ConcurrentHashMap.this.isEmpty();
49.1424 + }
49.1425 + public void clear() {
49.1426 + ConcurrentHashMap.this.clear();
49.1427 + }
49.1428 + }
49.1429 +
49.1430 + /* ---------------- Serialization Support -------------- */
49.1431 +
49.1432 + /**
49.1433 + * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
49.1434 + * stream (i.e., serialize it).
49.1435 + * @param s the stream
49.1436 + * @serialData
49.1437 + * the key (Object) and value (Object)
49.1438 + * for each key-value mapping, followed by a null pair.
49.1439 + * The key-value mappings are emitted in no particular order.
49.1440 + */
49.1441 + private void writeObject(java.io.ObjectOutputStream s) throws IOException {
49.1442 + // force all segments for serialization compatibility
49.1443 + for (int k = 0; k < segments.length; ++k)
49.1444 + ensureSegment(k);
49.1445 + s.defaultWriteObject();
49.1446 +
49.1447 + final Segment<K,V>[] segments = this.segments;
49.1448 + for (int k = 0; k < segments.length; ++k) {
49.1449 + Segment<K,V> seg = segmentAt(segments, k);
49.1450 + seg.lock();
49.1451 + try {
49.1452 + HashEntry<K,V>[] tab = seg.table;
49.1453 + for (int i = 0; i < tab.length; ++i) {
49.1454 + HashEntry<K,V> e;
49.1455 + for (e = entryAt(tab, i); e != null; e = e.next) {
49.1456 + s.writeObject(e.key);
49.1457 + s.writeObject(e.value);
49.1458 + }
49.1459 + }
49.1460 + } finally {
49.1461 + seg.unlock();
49.1462 + }
49.1463 + }
49.1464 + s.writeObject(null);
49.1465 + s.writeObject(null);
49.1466 + }
49.1467 +
49.1468 + /**
49.1469 + * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
49.1470 + * stream (i.e., deserialize it).
49.1471 + * @param s the stream
49.1472 + */
49.1473 + @SuppressWarnings("unchecked")
49.1474 + private void readObject(java.io.ObjectInputStream s)
49.1475 + throws IOException, ClassNotFoundException {
49.1476 + s.defaultReadObject();
49.1477 +
49.1478 + // Re-initialize segments to be minimally sized, and let grow.
49.1479 + int cap = MIN_SEGMENT_TABLE_CAPACITY;
49.1480 + final Segment<K,V>[] segments = this.segments;
49.1481 + for (int k = 0; k < segments.length; ++k) {
49.1482 + Segment<K,V> seg = segments[k];
49.1483 + if (seg != null) {
49.1484 + seg.threshold = (int)(cap * seg.loadFactor);
49.1485 + seg.table = (HashEntry<K,V>[]) new HashEntry[cap];
49.1486 + }
49.1487 + }
49.1488 +
49.1489 + // Read the keys and values, and put the mappings in the table
49.1490 + for (;;) {
49.1491 + K key = (K) s.readObject();
49.1492 + V value = (V) s.readObject();
49.1493 + if (key == null)
49.1494 + break;
49.1495 + put(key, value);
49.1496 + }
49.1497 + }
49.1498 +
49.1499 + // Unsafe mechanics
49.1500 + private static final sun.misc.Unsafe UNSAFE;
49.1501 + private static final long SBASE;
49.1502 + private static final int SSHIFT;
49.1503 + private static final long TBASE;
49.1504 + private static final int TSHIFT;
49.1505 +
49.1506 + static {
49.1507 + int ss, ts;
49.1508 + try {
49.1509 + UNSAFE = sun.misc.Unsafe.getUnsafe();
49.1510 + Class tc = HashEntry[].class;
49.1511 + Class sc = Segment[].class;
49.1512 + TBASE = UNSAFE.arrayBaseOffset(tc);
49.1513 + SBASE = UNSAFE.arrayBaseOffset(sc);
49.1514 + ts = UNSAFE.arrayIndexScale(tc);
49.1515 + ss = UNSAFE.arrayIndexScale(sc);
49.1516 + } catch (Exception e) {
49.1517 + throw new Error(e);
49.1518 + }
49.1519 + if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
49.1520 + throw new Error("data type scale not a power of two");
49.1521 + SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
49.1522 + TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
49.1523 + }
49.1524 +
49.1525 +}
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentMap.java Thu Oct 03 15:40:35 2013 +0200
50.3 @@ -0,0 +1,165 @@
50.4 +/*
50.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
50.6 + *
50.7 + * This code is free software; you can redistribute it and/or modify it
50.8 + * under the terms of the GNU General Public License version 2 only, as
50.9 + * published by the Free Software Foundation. Oracle designates this
50.10 + * particular file as subject to the "Classpath" exception as provided
50.11 + * by Oracle in the LICENSE file that accompanied this code.
50.12 + *
50.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
50.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
50.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
50.16 + * version 2 for more details (a copy is included in the LICENSE file that
50.17 + * accompanied this code).
50.18 + *
50.19 + * You should have received a copy of the GNU General Public License version
50.20 + * 2 along with this work; if not, write to the Free Software Foundation,
50.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
50.22 + *
50.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
50.24 + * or visit www.oracle.com if you need additional information or have any
50.25 + * questions.
50.26 + */
50.27 +
50.28 +/*
50.29 + * This file is available under and governed by the GNU General Public
50.30 + * License version 2 only, as published by the Free Software Foundation.
50.31 + * However, the following notice accompanied the original version of this
50.32 + * file:
50.33 + *
50.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
50.35 + * Expert Group and released to the public domain, as explained at
50.36 + * http://creativecommons.org/publicdomain/zero/1.0/
50.37 + */
50.38 +
50.39 +package java.util.concurrent;
50.40 +import java.util.Map;
50.41 +
50.42 +/**
50.43 + * A {@link java.util.Map} providing additional atomic
50.44 + * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods.
50.45 + *
50.46 + * <p>Memory consistency effects: As with other concurrent
50.47 + * collections, actions in a thread prior to placing an object into a
50.48 + * {@code ConcurrentMap} as a key or value
50.49 + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
50.50 + * actions subsequent to the access or removal of that object from
50.51 + * the {@code ConcurrentMap} in another thread.
50.52 + *
50.53 + * <p>This interface is a member of the
50.54 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
50.55 + * Java Collections Framework</a>.
50.56 + *
50.57 + * @since 1.5
50.58 + * @author Doug Lea
50.59 + * @param <K> the type of keys maintained by this map
50.60 + * @param <V> the type of mapped values
50.61 + */
50.62 +public interface ConcurrentMap<K, V> extends Map<K, V> {
50.63 + /**
50.64 + * If the specified key is not already associated
50.65 + * with a value, associate it with the given value.
50.66 + * This is equivalent to
50.67 + * <pre>
50.68 + * if (!map.containsKey(key))
50.69 + * return map.put(key, value);
50.70 + * else
50.71 + * return map.get(key);</pre>
50.72 + * except that the action is performed atomically.
50.73 + *
50.74 + * @param key key with which the specified value is to be associated
50.75 + * @param value value to be associated with the specified key
50.76 + * @return the previous value associated with the specified key, or
50.77 + * <tt>null</tt> if there was no mapping for the key.
50.78 + * (A <tt>null</tt> return can also indicate that the map
50.79 + * previously associated <tt>null</tt> with the key,
50.80 + * if the implementation supports null values.)
50.81 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
50.82 + * is not supported by this map
50.83 + * @throws ClassCastException if the class of the specified key or value
50.84 + * prevents it from being stored in this map
50.85 + * @throws NullPointerException if the specified key or value is null,
50.86 + * and this map does not permit null keys or values
50.87 + * @throws IllegalArgumentException if some property of the specified key
50.88 + * or value prevents it from being stored in this map
50.89 + *
50.90 + */
50.91 + V putIfAbsent(K key, V value);
50.92 +
50.93 + /**
50.94 + * Removes the entry for a key only if currently mapped to a given value.
50.95 + * This is equivalent to
50.96 + * <pre>
50.97 + * if (map.containsKey(key) && map.get(key).equals(value)) {
50.98 + * map.remove(key);
50.99 + * return true;
50.100 + * } else return false;</pre>
50.101 + * except that the action is performed atomically.
50.102 + *
50.103 + * @param key key with which the specified value is associated
50.104 + * @param value value expected to be associated with the specified key
50.105 + * @return <tt>true</tt> if the value was removed
50.106 + * @throws UnsupportedOperationException if the <tt>remove</tt> operation
50.107 + * is not supported by this map
50.108 + * @throws ClassCastException if the key or value is of an inappropriate
50.109 + * type for this map
50.110 + * (<a href="../Collection.html#optional-restrictions">optional</a>)
50.111 + * @throws NullPointerException if the specified key or value is null,
50.112 + * and this map does not permit null keys or values
50.113 + * (<a href="../Collection.html#optional-restrictions">optional</a>)
50.114 + */
50.115 + boolean remove(Object key, Object value);
50.116 +
50.117 + /**
50.118 + * Replaces the entry for a key only if currently mapped to a given value.
50.119 + * This is equivalent to
50.120 + * <pre>
50.121 + * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
50.122 + * map.put(key, newValue);
50.123 + * return true;
50.124 + * } else return false;</pre>
50.125 + * except that the action is performed atomically.
50.126 + *
50.127 + * @param key key with which the specified value is associated
50.128 + * @param oldValue value expected to be associated with the specified key
50.129 + * @param newValue value to be associated with the specified key
50.130 + * @return <tt>true</tt> if the value was replaced
50.131 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
50.132 + * is not supported by this map
50.133 + * @throws ClassCastException if the class of a specified key or value
50.134 + * prevents it from being stored in this map
50.135 + * @throws NullPointerException if a specified key or value is null,
50.136 + * and this map does not permit null keys or values
50.137 + * @throws IllegalArgumentException if some property of a specified key
50.138 + * or value prevents it from being stored in this map
50.139 + */
50.140 + boolean replace(K key, V oldValue, V newValue);
50.141 +
50.142 + /**
50.143 + * Replaces the entry for a key only if currently mapped to some value.
50.144 + * This is equivalent to
50.145 + * <pre>
50.146 + * if (map.containsKey(key)) {
50.147 + * return map.put(key, value);
50.148 + * } else return null;</pre>
50.149 + * except that the action is performed atomically.
50.150 + *
50.151 + * @param key key with which the specified value is associated
50.152 + * @param value value to be associated with the specified key
50.153 + * @return the previous value associated with the specified key, or
50.154 + * <tt>null</tt> if there was no mapping for the key.
50.155 + * (A <tt>null</tt> return can also indicate that the map
50.156 + * previously associated <tt>null</tt> with the key,
50.157 + * if the implementation supports null values.)
50.158 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
50.159 + * is not supported by this map
50.160 + * @throws ClassCastException if the class of the specified key or value
50.161 + * prevents it from being stored in this map
50.162 + * @throws NullPointerException if the specified key or value is null,
50.163 + * and this map does not permit null keys or values
50.164 + * @throws IllegalArgumentException if some property of the specified key
50.165 + * or value prevents it from being stored in this map
50.166 + */
50.167 + V replace(K key, V value);
50.168 +}
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
51.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java Thu Oct 03 15:40:35 2013 +0200
51.3 @@ -0,0 +1,164 @@
51.4 +/*
51.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
51.6 + *
51.7 + * This code is free software; you can redistribute it and/or modify it
51.8 + * under the terms of the GNU General Public License version 2 only, as
51.9 + * published by the Free Software Foundation. Oracle designates this
51.10 + * particular file as subject to the "Classpath" exception as provided
51.11 + * by Oracle in the LICENSE file that accompanied this code.
51.12 + *
51.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
51.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
51.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
51.16 + * version 2 for more details (a copy is included in the LICENSE file that
51.17 + * accompanied this code).
51.18 + *
51.19 + * You should have received a copy of the GNU General Public License version
51.20 + * 2 along with this work; if not, write to the Free Software Foundation,
51.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
51.22 + *
51.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
51.24 + * or visit www.oracle.com if you need additional information or have any
51.25 + * questions.
51.26 + */
51.27 +
51.28 +/*
51.29 + * This file is available under and governed by the GNU General Public
51.30 + * License version 2 only, as published by the Free Software Foundation.
51.31 + * However, the following notice accompanied the original version of this
51.32 + * file:
51.33 + *
51.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
51.35 + * Expert Group and released to the public domain, as explained at
51.36 + * http://creativecommons.org/publicdomain/zero/1.0/
51.37 + */
51.38 +
51.39 +package java.util.concurrent.atomic;
51.40 +import sun.misc.Unsafe;
51.41 +
51.42 +/**
51.43 + * A {@code boolean} value that may be updated atomically. See the
51.44 + * {@link java.util.concurrent.atomic} package specification for
51.45 + * description of the properties of atomic variables. An
51.46 + * {@code AtomicBoolean} is used in applications such as atomically
51.47 + * updated flags, and cannot be used as a replacement for a
51.48 + * {@link java.lang.Boolean}.
51.49 + *
51.50 + * @since 1.5
51.51 + * @author Doug Lea
51.52 + */
51.53 +public class AtomicBoolean implements java.io.Serializable {
51.54 + private static final long serialVersionUID = 4654671469794556979L;
51.55 + // setup to use Unsafe.compareAndSwapInt for updates
51.56 + private static final Unsafe unsafe = Unsafe.getUnsafe();
51.57 + private static final long valueOffset;
51.58 +
51.59 + static {
51.60 + try {
51.61 + valueOffset = unsafe.objectFieldOffset
51.62 + (AtomicBoolean.class.getDeclaredField("value"));
51.63 + } catch (Exception ex) { throw new Error(ex); }
51.64 + }
51.65 +
51.66 + private volatile int value;
51.67 +
51.68 + /**
51.69 + * Creates a new {@code AtomicBoolean} with the given initial value.
51.70 + *
51.71 + * @param initialValue the initial value
51.72 + */
51.73 + public AtomicBoolean(boolean initialValue) {
51.74 + value = initialValue ? 1 : 0;
51.75 + }
51.76 +
51.77 + /**
51.78 + * Creates a new {@code AtomicBoolean} with initial value {@code false}.
51.79 + */
51.80 + public AtomicBoolean() {
51.81 + }
51.82 +
51.83 + /**
51.84 + * Returns the current value.
51.85 + *
51.86 + * @return the current value
51.87 + */
51.88 + public final boolean get() {
51.89 + return value != 0;
51.90 + }
51.91 +
51.92 + /**
51.93 + * Atomically sets the value to the given updated value
51.94 + * if the current value {@code ==} the expected value.
51.95 + *
51.96 + * @param expect the expected value
51.97 + * @param update the new value
51.98 + * @return true if successful. False return indicates that
51.99 + * the actual value was not equal to the expected value.
51.100 + */
51.101 + public final boolean compareAndSet(boolean expect, boolean update) {
51.102 + int e = expect ? 1 : 0;
51.103 + int u = update ? 1 : 0;
51.104 + return unsafe.compareAndSwapInt(this, valueOffset, e, u);
51.105 + }
51.106 +
51.107 + /**
51.108 + * Atomically sets the value to the given updated value
51.109 + * if the current value {@code ==} the expected value.
51.110 + *
51.111 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
51.112 + * and does not provide ordering guarantees, so is only rarely an
51.113 + * appropriate alternative to {@code compareAndSet}.
51.114 + *
51.115 + * @param expect the expected value
51.116 + * @param update the new value
51.117 + * @return true if successful.
51.118 + */
51.119 + public boolean weakCompareAndSet(boolean expect, boolean update) {
51.120 + int e = expect ? 1 : 0;
51.121 + int u = update ? 1 : 0;
51.122 + return unsafe.compareAndSwapInt(this, valueOffset, e, u);
51.123 + }
51.124 +
51.125 + /**
51.126 + * Unconditionally sets to the given value.
51.127 + *
51.128 + * @param newValue the new value
51.129 + */
51.130 + public final void set(boolean newValue) {
51.131 + value = newValue ? 1 : 0;
51.132 + }
51.133 +
51.134 + /**
51.135 + * Eventually sets to the given value.
51.136 + *
51.137 + * @param newValue the new value
51.138 + * @since 1.6
51.139 + */
51.140 + public final void lazySet(boolean newValue) {
51.141 + int v = newValue ? 1 : 0;
51.142 + unsafe.putOrderedInt(this, valueOffset, v);
51.143 + }
51.144 +
51.145 + /**
51.146 + * Atomically sets to the given value and returns the previous value.
51.147 + *
51.148 + * @param newValue the new value
51.149 + * @return the previous value
51.150 + */
51.151 + public final boolean getAndSet(boolean newValue) {
51.152 + for (;;) {
51.153 + boolean current = get();
51.154 + if (compareAndSet(current, newValue))
51.155 + return current;
51.156 + }
51.157 + }
51.158 +
51.159 + /**
51.160 + * Returns the String representation of the current value.
51.161 + * @return the String representation of the current value.
51.162 + */
51.163 + public String toString() {
51.164 + return Boolean.toString(get());
51.165 + }
51.166 +
51.167 +}
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
52.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java Thu Oct 03 15:40:35 2013 +0200
52.3 @@ -0,0 +1,265 @@
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.atomic;
52.40 +import sun.misc.Unsafe;
52.41 +
52.42 +/**
52.43 + * An {@code int} value that may be updated atomically. See the
52.44 + * {@link java.util.concurrent.atomic} package specification for
52.45 + * description of the properties of atomic variables. An
52.46 + * {@code AtomicInteger} is used in applications such as atomically
52.47 + * incremented counters, and cannot be used as a replacement for an
52.48 + * {@link java.lang.Integer}. However, this class does extend
52.49 + * {@code Number} to allow uniform access by tools and utilities that
52.50 + * deal with numerically-based classes.
52.51 + *
52.52 + * @since 1.5
52.53 + * @author Doug Lea
52.54 +*/
52.55 +public class AtomicInteger extends Number implements java.io.Serializable {
52.56 + private static final long serialVersionUID = 6214790243416807050L;
52.57 +
52.58 + // setup to use Unsafe.compareAndSwapInt for updates
52.59 + private static final Unsafe unsafe = Unsafe.getUnsafe();
52.60 + private static final long valueOffset;
52.61 +
52.62 + static {
52.63 + try {
52.64 + valueOffset = unsafe.objectFieldOffset
52.65 + (AtomicInteger.class.getDeclaredField("value"));
52.66 + } catch (Exception ex) { throw new Error(ex); }
52.67 + }
52.68 +
52.69 + private volatile int value;
52.70 +
52.71 + /**
52.72 + * Creates a new AtomicInteger with the given initial value.
52.73 + *
52.74 + * @param initialValue the initial value
52.75 + */
52.76 + public AtomicInteger(int initialValue) {
52.77 + value = initialValue;
52.78 + }
52.79 +
52.80 + /**
52.81 + * Creates a new AtomicInteger with initial value {@code 0}.
52.82 + */
52.83 + public AtomicInteger() {
52.84 + }
52.85 +
52.86 + /**
52.87 + * Gets the current value.
52.88 + *
52.89 + * @return the current value
52.90 + */
52.91 + public final int get() {
52.92 + return value;
52.93 + }
52.94 +
52.95 + /**
52.96 + * Sets to the given value.
52.97 + *
52.98 + * @param newValue the new value
52.99 + */
52.100 + public final void set(int newValue) {
52.101 + value = newValue;
52.102 + }
52.103 +
52.104 + /**
52.105 + * Eventually sets to the given value.
52.106 + *
52.107 + * @param newValue the new value
52.108 + * @since 1.6
52.109 + */
52.110 + public final void lazySet(int newValue) {
52.111 + unsafe.putOrderedInt(this, valueOffset, newValue);
52.112 + }
52.113 +
52.114 + /**
52.115 + * Atomically sets to the given value and returns the old value.
52.116 + *
52.117 + * @param newValue the new value
52.118 + * @return the previous value
52.119 + */
52.120 + public final int getAndSet(int newValue) {
52.121 + for (;;) {
52.122 + int current = get();
52.123 + if (compareAndSet(current, newValue))
52.124 + return current;
52.125 + }
52.126 + }
52.127 +
52.128 + /**
52.129 + * Atomically sets the value to the given updated value
52.130 + * if the current value {@code ==} the expected value.
52.131 + *
52.132 + * @param expect the expected value
52.133 + * @param update the new value
52.134 + * @return true if successful. False return indicates that
52.135 + * the actual value was not equal to the expected value.
52.136 + */
52.137 + public final boolean compareAndSet(int expect, int update) {
52.138 + return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
52.139 + }
52.140 +
52.141 + /**
52.142 + * Atomically sets the value to the given updated value
52.143 + * if the current value {@code ==} the expected value.
52.144 + *
52.145 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
52.146 + * and does not provide ordering guarantees, so is only rarely an
52.147 + * appropriate alternative to {@code compareAndSet}.
52.148 + *
52.149 + * @param expect the expected value
52.150 + * @param update the new value
52.151 + * @return true if successful.
52.152 + */
52.153 + public final boolean weakCompareAndSet(int expect, int update) {
52.154 + return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
52.155 + }
52.156 +
52.157 + /**
52.158 + * Atomically increments by one the current value.
52.159 + *
52.160 + * @return the previous value
52.161 + */
52.162 + public final int getAndIncrement() {
52.163 + for (;;) {
52.164 + int current = get();
52.165 + int next = current + 1;
52.166 + if (compareAndSet(current, next))
52.167 + return current;
52.168 + }
52.169 + }
52.170 +
52.171 + /**
52.172 + * Atomically decrements by one the current value.
52.173 + *
52.174 + * @return the previous value
52.175 + */
52.176 + public final int getAndDecrement() {
52.177 + for (;;) {
52.178 + int current = get();
52.179 + int next = current - 1;
52.180 + if (compareAndSet(current, next))
52.181 + return current;
52.182 + }
52.183 + }
52.184 +
52.185 + /**
52.186 + * Atomically adds the given value to the current value.
52.187 + *
52.188 + * @param delta the value to add
52.189 + * @return the previous value
52.190 + */
52.191 + public final int getAndAdd(int delta) {
52.192 + for (;;) {
52.193 + int current = get();
52.194 + int next = current + delta;
52.195 + if (compareAndSet(current, next))
52.196 + return current;
52.197 + }
52.198 + }
52.199 +
52.200 + /**
52.201 + * Atomically increments by one the current value.
52.202 + *
52.203 + * @return the updated value
52.204 + */
52.205 + public final int incrementAndGet() {
52.206 + for (;;) {
52.207 + int current = get();
52.208 + int next = current + 1;
52.209 + if (compareAndSet(current, next))
52.210 + return next;
52.211 + }
52.212 + }
52.213 +
52.214 + /**
52.215 + * Atomically decrements by one the current value.
52.216 + *
52.217 + * @return the updated value
52.218 + */
52.219 + public final int decrementAndGet() {
52.220 + for (;;) {
52.221 + int current = get();
52.222 + int next = current - 1;
52.223 + if (compareAndSet(current, next))
52.224 + return next;
52.225 + }
52.226 + }
52.227 +
52.228 + /**
52.229 + * Atomically adds the given value to the current value.
52.230 + *
52.231 + * @param delta the value to add
52.232 + * @return the updated value
52.233 + */
52.234 + public final int addAndGet(int delta) {
52.235 + for (;;) {
52.236 + int current = get();
52.237 + int next = current + delta;
52.238 + if (compareAndSet(current, next))
52.239 + return next;
52.240 + }
52.241 + }
52.242 +
52.243 + /**
52.244 + * Returns the String representation of the current value.
52.245 + * @return the String representation of the current value.
52.246 + */
52.247 + public String toString() {
52.248 + return Integer.toString(get());
52.249 + }
52.250 +
52.251 +
52.252 + public int intValue() {
52.253 + return get();
52.254 + }
52.255 +
52.256 + public long longValue() {
52.257 + return (long)get();
52.258 + }
52.259 +
52.260 + public float floatValue() {
52.261 + return (float)get();
52.262 + }
52.263 +
52.264 + public double doubleValue() {
52.265 + return (double)get();
52.266 + }
52.267 +
52.268 +}
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
53.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java Thu Oct 03 15:40:35 2013 +0200
53.3 @@ -0,0 +1,284 @@
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.atomic;
53.40 +import sun.misc.Unsafe;
53.41 +import java.util.*;
53.42 +
53.43 +/**
53.44 + * An {@code int} array in which elements may be updated atomically.
53.45 + * See the {@link java.util.concurrent.atomic} package
53.46 + * specification for description of the properties of atomic
53.47 + * variables.
53.48 + * @since 1.5
53.49 + * @author Doug Lea
53.50 + */
53.51 +public class AtomicIntegerArray implements java.io.Serializable {
53.52 + private static final long serialVersionUID = 2862133569453604235L;
53.53 +
53.54 + private static final Unsafe unsafe = Unsafe.getUnsafe();
53.55 + private static final int base = unsafe.arrayBaseOffset(int[].class);
53.56 + private static final int shift;
53.57 + private final int[] array;
53.58 +
53.59 + static {
53.60 + int scale = unsafe.arrayIndexScale(int[].class);
53.61 + if ((scale & (scale - 1)) != 0)
53.62 + throw new Error("data type scale not a power of two");
53.63 + shift = 31 - Integer.numberOfLeadingZeros(scale);
53.64 + }
53.65 +
53.66 + private long checkedByteOffset(int i) {
53.67 + if (i < 0 || i >= array.length)
53.68 + throw new IndexOutOfBoundsException("index " + i);
53.69 +
53.70 + return byteOffset(i);
53.71 + }
53.72 +
53.73 + private static long byteOffset(int i) {
53.74 + return ((long) i << shift) + base;
53.75 + }
53.76 +
53.77 + /**
53.78 + * Creates a new AtomicIntegerArray of the given length, with all
53.79 + * elements initially zero.
53.80 + *
53.81 + * @param length the length of the array
53.82 + */
53.83 + public AtomicIntegerArray(int length) {
53.84 + array = new int[length];
53.85 + }
53.86 +
53.87 + /**
53.88 + * Creates a new AtomicIntegerArray with the same length as, and
53.89 + * all elements copied from, the given array.
53.90 + *
53.91 + * @param array the array to copy elements from
53.92 + * @throws NullPointerException if array is null
53.93 + */
53.94 + public AtomicIntegerArray(int[] array) {
53.95 + // Visibility guaranteed by final field guarantees
53.96 + this.array = array.clone();
53.97 + }
53.98 +
53.99 + /**
53.100 + * Returns the length of the array.
53.101 + *
53.102 + * @return the length of the array
53.103 + */
53.104 + public final int length() {
53.105 + return array.length;
53.106 + }
53.107 +
53.108 + /**
53.109 + * Gets the current value at position {@code i}.
53.110 + *
53.111 + * @param i the index
53.112 + * @return the current value
53.113 + */
53.114 + public final int get(int i) {
53.115 + return getRaw(checkedByteOffset(i));
53.116 + }
53.117 +
53.118 + private int getRaw(long offset) {
53.119 + return unsafe.getIntVolatile(array, offset);
53.120 + }
53.121 +
53.122 + /**
53.123 + * Sets the element at position {@code i} to the given value.
53.124 + *
53.125 + * @param i the index
53.126 + * @param newValue the new value
53.127 + */
53.128 + public final void set(int i, int newValue) {
53.129 + unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
53.130 + }
53.131 +
53.132 + /**
53.133 + * Eventually sets the element at position {@code i} to the given value.
53.134 + *
53.135 + * @param i the index
53.136 + * @param newValue the new value
53.137 + * @since 1.6
53.138 + */
53.139 + public final void lazySet(int i, int newValue) {
53.140 + unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
53.141 + }
53.142 +
53.143 + /**
53.144 + * Atomically sets the element at position {@code i} to the given
53.145 + * value and returns the old value.
53.146 + *
53.147 + * @param i the index
53.148 + * @param newValue the new value
53.149 + * @return the previous value
53.150 + */
53.151 + public final int getAndSet(int i, int newValue) {
53.152 + long offset = checkedByteOffset(i);
53.153 + while (true) {
53.154 + int current = getRaw(offset);
53.155 + if (compareAndSetRaw(offset, current, newValue))
53.156 + return current;
53.157 + }
53.158 + }
53.159 +
53.160 + /**
53.161 + * Atomically sets the element at position {@code i} to the given
53.162 + * updated value if the current value {@code ==} the expected value.
53.163 + *
53.164 + * @param i the index
53.165 + * @param expect the expected value
53.166 + * @param update the new value
53.167 + * @return true if successful. False return indicates that
53.168 + * the actual value was not equal to the expected value.
53.169 + */
53.170 + public final boolean compareAndSet(int i, int expect, int update) {
53.171 + return compareAndSetRaw(checkedByteOffset(i), expect, update);
53.172 + }
53.173 +
53.174 + private boolean compareAndSetRaw(long offset, int expect, int update) {
53.175 + return unsafe.compareAndSwapInt(array, offset, expect, update);
53.176 + }
53.177 +
53.178 + /**
53.179 + * Atomically sets the element at position {@code i} to the given
53.180 + * updated value if the current value {@code ==} the expected value.
53.181 + *
53.182 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
53.183 + * and does not provide ordering guarantees, so is only rarely an
53.184 + * appropriate alternative to {@code compareAndSet}.
53.185 + *
53.186 + * @param i the index
53.187 + * @param expect the expected value
53.188 + * @param update the new value
53.189 + * @return true if successful.
53.190 + */
53.191 + public final boolean weakCompareAndSet(int i, int expect, int update) {
53.192 + return compareAndSet(i, expect, update);
53.193 + }
53.194 +
53.195 + /**
53.196 + * Atomically increments by one the element at index {@code i}.
53.197 + *
53.198 + * @param i the index
53.199 + * @return the previous value
53.200 + */
53.201 + public final int getAndIncrement(int i) {
53.202 + return getAndAdd(i, 1);
53.203 + }
53.204 +
53.205 + /**
53.206 + * Atomically decrements by one the element at index {@code i}.
53.207 + *
53.208 + * @param i the index
53.209 + * @return the previous value
53.210 + */
53.211 + public final int getAndDecrement(int i) {
53.212 + return getAndAdd(i, -1);
53.213 + }
53.214 +
53.215 + /**
53.216 + * Atomically adds the given value to the element at index {@code i}.
53.217 + *
53.218 + * @param i the index
53.219 + * @param delta the value to add
53.220 + * @return the previous value
53.221 + */
53.222 + public final int getAndAdd(int i, int delta) {
53.223 + long offset = checkedByteOffset(i);
53.224 + while (true) {
53.225 + int current = getRaw(offset);
53.226 + if (compareAndSetRaw(offset, current, current + delta))
53.227 + return current;
53.228 + }
53.229 + }
53.230 +
53.231 + /**
53.232 + * Atomically increments by one the element at index {@code i}.
53.233 + *
53.234 + * @param i the index
53.235 + * @return the updated value
53.236 + */
53.237 + public final int incrementAndGet(int i) {
53.238 + return addAndGet(i, 1);
53.239 + }
53.240 +
53.241 + /**
53.242 + * Atomically decrements by one the element at index {@code i}.
53.243 + *
53.244 + * @param i the index
53.245 + * @return the updated value
53.246 + */
53.247 + public final int decrementAndGet(int i) {
53.248 + return addAndGet(i, -1);
53.249 + }
53.250 +
53.251 + /**
53.252 + * Atomically adds the given value to the element at index {@code i}.
53.253 + *
53.254 + * @param i the index
53.255 + * @param delta the value to add
53.256 + * @return the updated value
53.257 + */
53.258 + public final int addAndGet(int i, int delta) {
53.259 + long offset = checkedByteOffset(i);
53.260 + while (true) {
53.261 + int current = getRaw(offset);
53.262 + int next = current + delta;
53.263 + if (compareAndSetRaw(offset, current, next))
53.264 + return next;
53.265 + }
53.266 + }
53.267 +
53.268 + /**
53.269 + * Returns the String representation of the current values of array.
53.270 + * @return the String representation of the current values of array
53.271 + */
53.272 + public String toString() {
53.273 + int iMax = array.length - 1;
53.274 + if (iMax == -1)
53.275 + return "[]";
53.276 +
53.277 + StringBuilder b = new StringBuilder();
53.278 + b.append('[');
53.279 + for (int i = 0; ; i++) {
53.280 + b.append(getRaw(byteOffset(i)));
53.281 + if (i == iMax)
53.282 + return b.append(']').toString();
53.283 + b.append(',').append(' ');
53.284 + }
53.285 + }
53.286 +
53.287 +}
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/AtomicLong.java Thu Oct 03 15:40:35 2013 +0200
54.3 @@ -0,0 +1,279 @@
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 long} 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 AtomicLong} is used in applications such as atomically
54.47 + * incremented sequence numbers, and cannot be used as a replacement
54.48 + * for a {@link java.lang.Long}. However, this class does extend
54.49 + * {@code Number} to allow uniform access by tools and utilities that
54.50 + * deal with numerically-based classes.
54.51 + *
54.52 + * @since 1.5
54.53 + * @author Doug Lea
54.54 + */
54.55 +public class AtomicLong extends Number implements java.io.Serializable {
54.56 + private static final long serialVersionUID = 1927816293512124184L;
54.57 +
54.58 + // setup to use Unsafe.compareAndSwapLong for updates
54.59 + private static final Unsafe unsafe = Unsafe.getUnsafe();
54.60 + private static final long valueOffset;
54.61 +
54.62 + /**
54.63 + * Records whether the underlying JVM supports lockless
54.64 + * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
54.65 + * method works in either case, some constructions should be
54.66 + * handled at Java level to avoid locking user-visible locks.
54.67 + */
54.68 + static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
54.69 +
54.70 + /**
54.71 + * Returns whether underlying JVM supports lockless CompareAndSet
54.72 + * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
54.73 + */
54.74 + private static native boolean VMSupportsCS8();
54.75 +
54.76 + static {
54.77 + try {
54.78 + valueOffset = unsafe.objectFieldOffset
54.79 + (AtomicLong.class.getDeclaredField("value"));
54.80 + } catch (Exception ex) { throw new Error(ex); }
54.81 + }
54.82 +
54.83 + private volatile long value;
54.84 +
54.85 + /**
54.86 + * Creates a new AtomicLong with the given initial value.
54.87 + *
54.88 + * @param initialValue the initial value
54.89 + */
54.90 + public AtomicLong(long initialValue) {
54.91 + value = initialValue;
54.92 + }
54.93 +
54.94 + /**
54.95 + * Creates a new AtomicLong with initial value {@code 0}.
54.96 + */
54.97 + public AtomicLong() {
54.98 + }
54.99 +
54.100 + /**
54.101 + * Gets the current value.
54.102 + *
54.103 + * @return the current value
54.104 + */
54.105 + public final long get() {
54.106 + return value;
54.107 + }
54.108 +
54.109 + /**
54.110 + * Sets to the given value.
54.111 + *
54.112 + * @param newValue the new value
54.113 + */
54.114 + public final void set(long newValue) {
54.115 + value = newValue;
54.116 + }
54.117 +
54.118 + /**
54.119 + * Eventually sets to the given value.
54.120 + *
54.121 + * @param newValue the new value
54.122 + * @since 1.6
54.123 + */
54.124 + public final void lazySet(long newValue) {
54.125 + unsafe.putOrderedLong(this, valueOffset, newValue);
54.126 + }
54.127 +
54.128 + /**
54.129 + * Atomically sets to the given value and returns the old value.
54.130 + *
54.131 + * @param newValue the new value
54.132 + * @return the previous value
54.133 + */
54.134 + public final long getAndSet(long newValue) {
54.135 + while (true) {
54.136 + long current = get();
54.137 + if (compareAndSet(current, newValue))
54.138 + return current;
54.139 + }
54.140 + }
54.141 +
54.142 + /**
54.143 + * Atomically sets the value to the given updated value
54.144 + * if the current value {@code ==} the expected value.
54.145 + *
54.146 + * @param expect the expected value
54.147 + * @param update the new value
54.148 + * @return true if successful. False return indicates that
54.149 + * the actual value was not equal to the expected value.
54.150 + */
54.151 + public final boolean compareAndSet(long expect, long update) {
54.152 + return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
54.153 + }
54.154 +
54.155 + /**
54.156 + * Atomically sets the value to the given updated value
54.157 + * if the current value {@code ==} the expected value.
54.158 + *
54.159 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
54.160 + * and does not provide ordering guarantees, so is only rarely an
54.161 + * appropriate alternative to {@code compareAndSet}.
54.162 + *
54.163 + * @param expect the expected value
54.164 + * @param update the new value
54.165 + * @return true if successful.
54.166 + */
54.167 + public final boolean weakCompareAndSet(long expect, long update) {
54.168 + return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
54.169 + }
54.170 +
54.171 + /**
54.172 + * Atomically increments by one the current value.
54.173 + *
54.174 + * @return the previous value
54.175 + */
54.176 + public final long getAndIncrement() {
54.177 + while (true) {
54.178 + long current = get();
54.179 + long next = current + 1;
54.180 + if (compareAndSet(current, next))
54.181 + return current;
54.182 + }
54.183 + }
54.184 +
54.185 + /**
54.186 + * Atomically decrements by one the current value.
54.187 + *
54.188 + * @return the previous value
54.189 + */
54.190 + public final long getAndDecrement() {
54.191 + while (true) {
54.192 + long current = get();
54.193 + long next = current - 1;
54.194 + if (compareAndSet(current, next))
54.195 + return current;
54.196 + }
54.197 + }
54.198 +
54.199 + /**
54.200 + * Atomically adds the given value to the current value.
54.201 + *
54.202 + * @param delta the value to add
54.203 + * @return the previous value
54.204 + */
54.205 + public final long getAndAdd(long delta) {
54.206 + while (true) {
54.207 + long current = get();
54.208 + long next = current + delta;
54.209 + if (compareAndSet(current, next))
54.210 + return current;
54.211 + }
54.212 + }
54.213 +
54.214 + /**
54.215 + * Atomically increments by one the current value.
54.216 + *
54.217 + * @return the updated value
54.218 + */
54.219 + public final long incrementAndGet() {
54.220 + for (;;) {
54.221 + long current = get();
54.222 + long next = current + 1;
54.223 + if (compareAndSet(current, next))
54.224 + return next;
54.225 + }
54.226 + }
54.227 +
54.228 + /**
54.229 + * Atomically decrements by one the current value.
54.230 + *
54.231 + * @return the updated value
54.232 + */
54.233 + public final long decrementAndGet() {
54.234 + for (;;) {
54.235 + long current = get();
54.236 + long next = current - 1;
54.237 + if (compareAndSet(current, next))
54.238 + return next;
54.239 + }
54.240 + }
54.241 +
54.242 + /**
54.243 + * Atomically adds the given value to the current value.
54.244 + *
54.245 + * @param delta the value to add
54.246 + * @return the updated value
54.247 + */
54.248 + public final long addAndGet(long delta) {
54.249 + for (;;) {
54.250 + long current = get();
54.251 + long next = current + delta;
54.252 + if (compareAndSet(current, next))
54.253 + return next;
54.254 + }
54.255 + }
54.256 +
54.257 + /**
54.258 + * Returns the String representation of the current value.
54.259 + * @return the String representation of the current value.
54.260 + */
54.261 + public String toString() {
54.262 + return Long.toString(get());
54.263 + }
54.264 +
54.265 +
54.266 + public int intValue() {
54.267 + return (int)get();
54.268 + }
54.269 +
54.270 + public long longValue() {
54.271 + return get();
54.272 + }
54.273 +
54.274 + public float floatValue() {
54.275 + return (float)get();
54.276 + }
54.277 +
54.278 + public double doubleValue() {
54.279 + return (double)get();
54.280 + }
54.281 +
54.282 +}
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/AtomicLongArray.java Thu Oct 03 15:40:35 2013 +0200
55.3 @@ -0,0 +1,284 @@
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 +import java.util.*;
55.42 +
55.43 +/**
55.44 + * A {@code long} array in which elements may be updated atomically.
55.45 + * See the {@link java.util.concurrent.atomic} package specification
55.46 + * for description of the properties of atomic variables.
55.47 + * @since 1.5
55.48 + * @author Doug Lea
55.49 + */
55.50 +public class AtomicLongArray implements java.io.Serializable {
55.51 + private static final long serialVersionUID = -2308431214976778248L;
55.52 +
55.53 + private static final Unsafe unsafe = Unsafe.getUnsafe();
55.54 + private static final int base = unsafe.arrayBaseOffset(long[].class);
55.55 + private static final int shift;
55.56 + private final long[] array;
55.57 +
55.58 + static {
55.59 + int scale = unsafe.arrayIndexScale(long[].class);
55.60 + if ((scale & (scale - 1)) != 0)
55.61 + throw new Error("data type scale not a power of two");
55.62 + shift = 31 - Integer.numberOfLeadingZeros(scale);
55.63 + }
55.64 +
55.65 + private long checkedByteOffset(int i) {
55.66 + if (i < 0 || i >= array.length)
55.67 + throw new IndexOutOfBoundsException("index " + i);
55.68 +
55.69 + return byteOffset(i);
55.70 + }
55.71 +
55.72 + private static long byteOffset(int i) {
55.73 + return ((long) i << shift) + base;
55.74 + }
55.75 +
55.76 + /**
55.77 + * Creates a new AtomicLongArray of the given length, with all
55.78 + * elements initially zero.
55.79 + *
55.80 + * @param length the length of the array
55.81 + */
55.82 + public AtomicLongArray(int length) {
55.83 + array = new long[length];
55.84 + }
55.85 +
55.86 + /**
55.87 + * Creates a new AtomicLongArray with the same length as, and
55.88 + * all elements copied from, the given array.
55.89 + *
55.90 + * @param array the array to copy elements from
55.91 + * @throws NullPointerException if array is null
55.92 + */
55.93 + public AtomicLongArray(long[] array) {
55.94 + // Visibility guaranteed by final field guarantees
55.95 + this.array = array.clone();
55.96 + }
55.97 +
55.98 + /**
55.99 + * Returns the length of the array.
55.100 + *
55.101 + * @return the length of the array
55.102 + */
55.103 + public final int length() {
55.104 + return array.length;
55.105 + }
55.106 +
55.107 + /**
55.108 + * Gets the current value at position {@code i}.
55.109 + *
55.110 + * @param i the index
55.111 + * @return the current value
55.112 + */
55.113 + public final long get(int i) {
55.114 + return getRaw(checkedByteOffset(i));
55.115 + }
55.116 +
55.117 + private long getRaw(long offset) {
55.118 + return unsafe.getLongVolatile(array, offset);
55.119 + }
55.120 +
55.121 + /**
55.122 + * Sets the element at position {@code i} to the given value.
55.123 + *
55.124 + * @param i the index
55.125 + * @param newValue the new value
55.126 + */
55.127 + public final void set(int i, long newValue) {
55.128 + unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
55.129 + }
55.130 +
55.131 + /**
55.132 + * Eventually sets the element at position {@code i} to the given value.
55.133 + *
55.134 + * @param i the index
55.135 + * @param newValue the new value
55.136 + * @since 1.6
55.137 + */
55.138 + public final void lazySet(int i, long newValue) {
55.139 + unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
55.140 + }
55.141 +
55.142 +
55.143 + /**
55.144 + * Atomically sets the element at position {@code i} to the given value
55.145 + * and returns the old value.
55.146 + *
55.147 + * @param i the index
55.148 + * @param newValue the new value
55.149 + * @return the previous value
55.150 + */
55.151 + public final long getAndSet(int i, long newValue) {
55.152 + long offset = checkedByteOffset(i);
55.153 + while (true) {
55.154 + long current = getRaw(offset);
55.155 + if (compareAndSetRaw(offset, current, newValue))
55.156 + return current;
55.157 + }
55.158 + }
55.159 +
55.160 + /**
55.161 + * Atomically sets the element at position {@code i} to the given
55.162 + * updated value if the current value {@code ==} the expected value.
55.163 + *
55.164 + * @param i the index
55.165 + * @param expect the expected value
55.166 + * @param update the new value
55.167 + * @return true if successful. False return indicates that
55.168 + * the actual value was not equal to the expected value.
55.169 + */
55.170 + public final boolean compareAndSet(int i, long expect, long update) {
55.171 + return compareAndSetRaw(checkedByteOffset(i), expect, update);
55.172 + }
55.173 +
55.174 + private boolean compareAndSetRaw(long offset, long expect, long update) {
55.175 + return unsafe.compareAndSwapLong(array, offset, expect, update);
55.176 + }
55.177 +
55.178 + /**
55.179 + * Atomically sets the element at position {@code i} to the given
55.180 + * updated value if the current value {@code ==} the expected value.
55.181 + *
55.182 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
55.183 + * and does not provide ordering guarantees, so is only rarely an
55.184 + * appropriate alternative to {@code compareAndSet}.
55.185 + *
55.186 + * @param i the index
55.187 + * @param expect the expected value
55.188 + * @param update the new value
55.189 + * @return true if successful.
55.190 + */
55.191 + public final boolean weakCompareAndSet(int i, long expect, long update) {
55.192 + return compareAndSet(i, expect, update);
55.193 + }
55.194 +
55.195 + /**
55.196 + * Atomically increments by one the element at index {@code i}.
55.197 + *
55.198 + * @param i the index
55.199 + * @return the previous value
55.200 + */
55.201 + public final long getAndIncrement(int i) {
55.202 + return getAndAdd(i, 1);
55.203 + }
55.204 +
55.205 + /**
55.206 + * Atomically decrements by one the element at index {@code i}.
55.207 + *
55.208 + * @param i the index
55.209 + * @return the previous value
55.210 + */
55.211 + public final long getAndDecrement(int i) {
55.212 + return getAndAdd(i, -1);
55.213 + }
55.214 +
55.215 + /**
55.216 + * Atomically adds the given value to the element at index {@code i}.
55.217 + *
55.218 + * @param i the index
55.219 + * @param delta the value to add
55.220 + * @return the previous value
55.221 + */
55.222 + public final long getAndAdd(int i, long delta) {
55.223 + long offset = checkedByteOffset(i);
55.224 + while (true) {
55.225 + long current = getRaw(offset);
55.226 + if (compareAndSetRaw(offset, current, current + delta))
55.227 + return current;
55.228 + }
55.229 + }
55.230 +
55.231 + /**
55.232 + * Atomically increments by one the element at index {@code i}.
55.233 + *
55.234 + * @param i the index
55.235 + * @return the updated value
55.236 + */
55.237 + public final long incrementAndGet(int i) {
55.238 + return addAndGet(i, 1);
55.239 + }
55.240 +
55.241 + /**
55.242 + * Atomically decrements by one the element at index {@code i}.
55.243 + *
55.244 + * @param i the index
55.245 + * @return the updated value
55.246 + */
55.247 + public final long decrementAndGet(int i) {
55.248 + return addAndGet(i, -1);
55.249 + }
55.250 +
55.251 + /**
55.252 + * Atomically adds the given value to the element at index {@code i}.
55.253 + *
55.254 + * @param i the index
55.255 + * @param delta the value to add
55.256 + * @return the updated value
55.257 + */
55.258 + public long addAndGet(int i, long delta) {
55.259 + long offset = checkedByteOffset(i);
55.260 + while (true) {
55.261 + long current = getRaw(offset);
55.262 + long next = current + delta;
55.263 + if (compareAndSetRaw(offset, current, next))
55.264 + return next;
55.265 + }
55.266 + }
55.267 +
55.268 + /**
55.269 + * Returns the String representation of the current values of array.
55.270 + * @return the String representation of the current values of array
55.271 + */
55.272 + public String toString() {
55.273 + int iMax = array.length - 1;
55.274 + if (iMax == -1)
55.275 + return "[]";
55.276 +
55.277 + StringBuilder b = new StringBuilder();
55.278 + b.append('[');
55.279 + for (int i = 0; ; i++) {
55.280 + b.append(getRaw(byteOffset(i)));
55.281 + if (i == iMax)
55.282 + return b.append(']').toString();
55.283 + b.append(',').append(' ');
55.284 + }
55.285 + }
55.286 +
55.287 +}
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/AtomicReference.java Thu Oct 03 15:40:35 2013 +0200
56.3 @@ -0,0 +1,155 @@
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 +
56.42 +/**
56.43 + * An object reference that may be updated atomically. See the {@link
56.44 + * java.util.concurrent.atomic} package specification for description
56.45 + * of the properties of atomic variables.
56.46 + * @since 1.5
56.47 + * @author Doug Lea
56.48 + * @param <V> The type of object referred to by this reference
56.49 + */
56.50 +public class AtomicReference<V> implements java.io.Serializable {
56.51 + private static final long serialVersionUID = -1848883965231344442L;
56.52 +
56.53 + private static final Unsafe unsafe = Unsafe.getUnsafe();
56.54 + private static final long valueOffset;
56.55 +
56.56 + static {
56.57 + try {
56.58 + valueOffset = unsafe.objectFieldOffset
56.59 + (AtomicReference.class.getDeclaredField("value"));
56.60 + } catch (Exception ex) { throw new Error(ex); }
56.61 + }
56.62 +
56.63 + private volatile V value;
56.64 +
56.65 + /**
56.66 + * Creates a new AtomicReference with the given initial value.
56.67 + *
56.68 + * @param initialValue the initial value
56.69 + */
56.70 + public AtomicReference(V initialValue) {
56.71 + value = initialValue;
56.72 + }
56.73 +
56.74 + /**
56.75 + * Creates a new AtomicReference with null initial value.
56.76 + */
56.77 + public AtomicReference() {
56.78 + }
56.79 +
56.80 + /**
56.81 + * Gets the current value.
56.82 + *
56.83 + * @return the current value
56.84 + */
56.85 + public final V get() {
56.86 + return value;
56.87 + }
56.88 +
56.89 + /**
56.90 + * Sets to the given value.
56.91 + *
56.92 + * @param newValue the new value
56.93 + */
56.94 + public final void set(V newValue) {
56.95 + value = newValue;
56.96 + }
56.97 +
56.98 + /**
56.99 + * Eventually sets to the given value.
56.100 + *
56.101 + * @param newValue the new value
56.102 + * @since 1.6
56.103 + */
56.104 + public final void lazySet(V newValue) {
56.105 + unsafe.putOrderedObject(this, valueOffset, newValue);
56.106 + }
56.107 +
56.108 + /**
56.109 + * Atomically sets the value to the given updated value
56.110 + * if the current value {@code ==} the expected value.
56.111 + * @param expect the expected value
56.112 + * @param update the new value
56.113 + * @return true if successful. False return indicates that
56.114 + * the actual value was not equal to the expected value.
56.115 + */
56.116 + public final boolean compareAndSet(V expect, V update) {
56.117 + return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
56.118 + }
56.119 +
56.120 + /**
56.121 + * Atomically sets the value to the given updated value
56.122 + * if the current value {@code ==} the expected value.
56.123 + *
56.124 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
56.125 + * and does not provide ordering guarantees, so is only rarely an
56.126 + * appropriate alternative to {@code compareAndSet}.
56.127 + *
56.128 + * @param expect the expected value
56.129 + * @param update the new value
56.130 + * @return true if successful.
56.131 + */
56.132 + public final boolean weakCompareAndSet(V expect, V update) {
56.133 + return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
56.134 + }
56.135 +
56.136 + /**
56.137 + * Atomically sets to the given value and returns the old value.
56.138 + *
56.139 + * @param newValue the new value
56.140 + * @return the previous value
56.141 + */
56.142 + public final V getAndSet(V newValue) {
56.143 + while (true) {
56.144 + V x = get();
56.145 + if (compareAndSet(x, newValue))
56.146 + return x;
56.147 + }
56.148 + }
56.149 +
56.150 + /**
56.151 + * Returns the String representation of the current value.
56.152 + * @return the String representation of the current value.
56.153 + */
56.154 + public String toString() {
56.155 + return String.valueOf(get());
56.156 + }
56.157 +
56.158 +}
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/AtomicReferenceArray.java Thu Oct 03 15:40:35 2013 +0200
57.3 @@ -0,0 +1,213 @@
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 +import java.util.*;
57.42 +
57.43 +/**
57.44 + * An array of object references in which elements may be updated
57.45 + * atomically. See the {@link java.util.concurrent.atomic} package
57.46 + * specification for description of the properties of atomic
57.47 + * variables.
57.48 + * @since 1.5
57.49 + * @author Doug Lea
57.50 + * @param <E> The base class of elements held in this array
57.51 + */
57.52 +public class AtomicReferenceArray<E> implements java.io.Serializable {
57.53 + private static final long serialVersionUID = -6209656149925076980L;
57.54 +
57.55 + private static final Unsafe unsafe = Unsafe.getUnsafe();
57.56 + private static final int base = unsafe.arrayBaseOffset(Object[].class);
57.57 + private static final int shift;
57.58 + private final Object[] array;
57.59 +
57.60 + static {
57.61 + int scale = unsafe.arrayIndexScale(Object[].class);
57.62 + if ((scale & (scale - 1)) != 0)
57.63 + throw new Error("data type scale not a power of two");
57.64 + shift = 31 - Integer.numberOfLeadingZeros(scale);
57.65 + }
57.66 +
57.67 + private long checkedByteOffset(int i) {
57.68 + if (i < 0 || i >= array.length)
57.69 + throw new IndexOutOfBoundsException("index " + i);
57.70 +
57.71 + return byteOffset(i);
57.72 + }
57.73 +
57.74 + private static long byteOffset(int i) {
57.75 + return ((long) i << shift) + base;
57.76 + }
57.77 +
57.78 + /**
57.79 + * Creates a new AtomicReferenceArray of the given length, with all
57.80 + * elements initially null.
57.81 + *
57.82 + * @param length the length of the array
57.83 + */
57.84 + public AtomicReferenceArray(int length) {
57.85 + array = new Object[length];
57.86 + }
57.87 +
57.88 + /**
57.89 + * Creates a new AtomicReferenceArray with the same length as, and
57.90 + * all elements copied from, the given array.
57.91 + *
57.92 + * @param array the array to copy elements from
57.93 + * @throws NullPointerException if array is null
57.94 + */
57.95 + public AtomicReferenceArray(E[] array) {
57.96 + // Visibility guaranteed by final field guarantees
57.97 + this.array = array.clone();
57.98 + }
57.99 +
57.100 + /**
57.101 + * Returns the length of the array.
57.102 + *
57.103 + * @return the length of the array
57.104 + */
57.105 + public final int length() {
57.106 + return array.length;
57.107 + }
57.108 +
57.109 + /**
57.110 + * Gets the current value at position {@code i}.
57.111 + *
57.112 + * @param i the index
57.113 + * @return the current value
57.114 + */
57.115 + public final E get(int i) {
57.116 + return getRaw(checkedByteOffset(i));
57.117 + }
57.118 +
57.119 + private E getRaw(long offset) {
57.120 + return (E) unsafe.getObjectVolatile(array, offset);
57.121 + }
57.122 +
57.123 + /**
57.124 + * Sets the element at position {@code i} to the given value.
57.125 + *
57.126 + * @param i the index
57.127 + * @param newValue the new value
57.128 + */
57.129 + public final void set(int i, E newValue) {
57.130 + unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
57.131 + }
57.132 +
57.133 + /**
57.134 + * Eventually sets the element at position {@code i} to the given value.
57.135 + *
57.136 + * @param i the index
57.137 + * @param newValue the new value
57.138 + * @since 1.6
57.139 + */
57.140 + public final void lazySet(int i, E newValue) {
57.141 + unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
57.142 + }
57.143 +
57.144 +
57.145 + /**
57.146 + * Atomically sets the element at position {@code i} to the given
57.147 + * value and returns the old value.
57.148 + *
57.149 + * @param i the index
57.150 + * @param newValue the new value
57.151 + * @return the previous value
57.152 + */
57.153 + public final E getAndSet(int i, E newValue) {
57.154 + long offset = checkedByteOffset(i);
57.155 + while (true) {
57.156 + E current = (E) getRaw(offset);
57.157 + if (compareAndSetRaw(offset, current, newValue))
57.158 + return current;
57.159 + }
57.160 + }
57.161 +
57.162 + /**
57.163 + * Atomically sets the element at position {@code i} to the given
57.164 + * updated value if the current value {@code ==} the expected value.
57.165 + *
57.166 + * @param i the index
57.167 + * @param expect the expected value
57.168 + * @param update the new value
57.169 + * @return true if successful. False return indicates that
57.170 + * the actual value was not equal to the expected value.
57.171 + */
57.172 + public final boolean compareAndSet(int i, E expect, E update) {
57.173 + return compareAndSetRaw(checkedByteOffset(i), expect, update);
57.174 + }
57.175 +
57.176 + private boolean compareAndSetRaw(long offset, E expect, E update) {
57.177 + return unsafe.compareAndSwapObject(array, offset, expect, update);
57.178 + }
57.179 +
57.180 + /**
57.181 + * Atomically sets the element at position {@code i} to the given
57.182 + * updated value if the current value {@code ==} the expected value.
57.183 + *
57.184 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
57.185 + * and does not provide ordering guarantees, so is only rarely an
57.186 + * appropriate alternative to {@code compareAndSet}.
57.187 + *
57.188 + * @param i the index
57.189 + * @param expect the expected value
57.190 + * @param update the new value
57.191 + * @return true if successful.
57.192 + */
57.193 + public final boolean weakCompareAndSet(int i, E expect, E update) {
57.194 + return compareAndSet(i, expect, update);
57.195 + }
57.196 +
57.197 + /**
57.198 + * Returns the String representation of the current values of array.
57.199 + * @return the String representation of the current values of array
57.200 + */
57.201 + public String toString() {
57.202 + int iMax = array.length - 1;
57.203 + if (iMax == -1)
57.204 + return "[]";
57.205 +
57.206 + StringBuilder b = new StringBuilder();
57.207 + b.append('[');
57.208 + for (int i = 0; ; i++) {
57.209 + b.append(getRaw(byteOffset(i)));
57.210 + if (i == iMax)
57.211 + return b.append(']').toString();
57.212 + b.append(',').append(' ');
57.213 + }
57.214 + }
57.215 +
57.216 +}
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/package-info.java Thu Oct 03 15:40:35 2013 +0200
58.3 @@ -0,0 +1,199 @@
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 +/**
58.40 + * A small toolkit of classes that support lock-free thread-safe
58.41 + * programming on single variables. In essence, the classes in this
58.42 + * package extend the notion of {@code volatile} values, fields, and
58.43 + * array elements to those that also provide an atomic conditional update
58.44 + * operation of the form:
58.45 + *
58.46 + * <pre>
58.47 + * boolean compareAndSet(expectedValue, updateValue);
58.48 + * </pre>
58.49 + *
58.50 + * <p>This method (which varies in argument types across different
58.51 + * classes) atomically sets a variable to the {@code updateValue} if it
58.52 + * currently holds the {@code expectedValue}, reporting {@code true} on
58.53 + * success. The classes in this package also contain methods to get and
58.54 + * unconditionally set values, as well as a weaker conditional atomic
58.55 + * update operation {@code weakCompareAndSet} described below.
58.56 + *
58.57 + * <p>The specifications of these methods enable implementations to
58.58 + * employ efficient machine-level atomic instructions that are available
58.59 + * on contemporary processors. However on some platforms, support may
58.60 + * entail some form of internal locking. Thus the methods are not
58.61 + * strictly guaranteed to be non-blocking --
58.62 + * a thread may block transiently before performing the operation.
58.63 + *
58.64 + * <p>Instances of classes
58.65 + * {@link java.util.concurrent.atomic.AtomicBoolean},
58.66 + * {@link java.util.concurrent.atomic.AtomicInteger},
58.67 + * {@link java.util.concurrent.atomic.AtomicLong}, and
58.68 + * {@link java.util.concurrent.atomic.AtomicReference}
58.69 + * each provide access and updates to a single variable of the
58.70 + * corresponding type. Each class also provides appropriate utility
58.71 + * methods for that type. For example, classes {@code AtomicLong} and
58.72 + * {@code AtomicInteger} provide atomic increment methods. One
58.73 + * application is to generate sequence numbers, as in:
58.74 + *
58.75 + * <pre>
58.76 + * class Sequencer {
58.77 + * private final AtomicLong sequenceNumber
58.78 + * = new AtomicLong(0);
58.79 + * public long next() {
58.80 + * return sequenceNumber.getAndIncrement();
58.81 + * }
58.82 + * }
58.83 + * </pre>
58.84 + *
58.85 + * <p>The memory effects for accesses and updates of atomics generally
58.86 + * follow the rules for volatiles, as stated in section 17.4 of
58.87 + * <cite>The Java™ Language Specification</cite>.
58.88 + *
58.89 + * <ul>
58.90 + *
58.91 + * <li> {@code get} has the memory effects of reading a
58.92 + * {@code volatile} variable.
58.93 + *
58.94 + * <li> {@code set} has the memory effects of writing (assigning) a
58.95 + * {@code volatile} variable.
58.96 + *
58.97 + * <li> {@code lazySet} has the memory effects of writing (assigning)
58.98 + * a {@code volatile} variable except that it permits reorderings with
58.99 + * subsequent (but not previous) memory actions that do not themselves
58.100 + * impose reordering constraints with ordinary non-{@code volatile}
58.101 + * writes. Among other usage contexts, {@code lazySet} may apply when
58.102 + * nulling out, for the sake of garbage collection, a reference that is
58.103 + * never accessed again.
58.104 + *
58.105 + * <li>{@code weakCompareAndSet} atomically reads and conditionally
58.106 + * writes a variable but does <em>not</em>
58.107 + * create any happens-before orderings, so provides no guarantees
58.108 + * with respect to previous or subsequent reads and writes of any
58.109 + * variables other than the target of the {@code weakCompareAndSet}.
58.110 + *
58.111 + * <li> {@code compareAndSet}
58.112 + * and all other read-and-update operations such as {@code getAndIncrement}
58.113 + * have the memory effects of both reading and
58.114 + * writing {@code volatile} variables.
58.115 + * </ul>
58.116 + *
58.117 + * <p>In addition to classes representing single values, this package
58.118 + * contains <em>Updater</em> classes that can be used to obtain
58.119 + * {@code compareAndSet} operations on any selected {@code volatile}
58.120 + * field of any selected class.
58.121 + *
58.122 + * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
58.123 + * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
58.124 + * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
58.125 + * reflection-based utilities that provide access to the associated
58.126 + * field types. These are mainly of use in atomic data structures in
58.127 + * which several {@code volatile} fields of the same node (for
58.128 + * example, the links of a tree node) are independently subject to
58.129 + * atomic updates. These classes enable greater flexibility in how
58.130 + * and when to use atomic updates, at the expense of more awkward
58.131 + * reflection-based setup, less convenient usage, and weaker
58.132 + * guarantees.
58.133 + *
58.134 + * <p>The
58.135 + * {@link java.util.concurrent.atomic.AtomicIntegerArray},
58.136 + * {@link java.util.concurrent.atomic.AtomicLongArray}, and
58.137 + * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
58.138 + * further extend atomic operation support to arrays of these types.
58.139 + * These classes are also notable in providing {@code volatile} access
58.140 + * semantics for their array elements, which is not supported for
58.141 + * ordinary arrays.
58.142 + *
58.143 + * <a name="Spurious">
58.144 + * <p>The atomic classes also support method {@code weakCompareAndSet},
58.145 + * which has limited applicability. On some platforms, the weak version
58.146 + * may be more efficient than {@code compareAndSet} in the normal case,
58.147 + * but differs in that any given invocation of the
58.148 + * {@code weakCompareAndSet} method may return {@code false}
58.149 + * <em>spuriously</em> (that is, for no apparent reason)</a>. A
58.150 + * {@code false} return means only that the operation may be retried if
58.151 + * desired, relying on the guarantee that repeated invocation when the
58.152 + * variable holds {@code expectedValue} and no other thread is also
58.153 + * attempting to set the variable will eventually succeed. (Such
58.154 + * spurious failures may for example be due to memory contention effects
58.155 + * that are unrelated to whether the expected and current values are
58.156 + * equal.) Additionally {@code weakCompareAndSet} does not provide
58.157 + * ordering guarantees that are usually needed for synchronization
58.158 + * control. However, the method may be useful for updating counters and
58.159 + * statistics when such updates are unrelated to the other
58.160 + * happens-before orderings of a program. When a thread sees an update
58.161 + * to an atomic variable caused by a {@code weakCompareAndSet}, it does
58.162 + * not necessarily see updates to any <em>other</em> variables that
58.163 + * occurred before the {@code weakCompareAndSet}. This may be
58.164 + * acceptable when, for example, updating performance statistics, but
58.165 + * rarely otherwise.
58.166 + *
58.167 + * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
58.168 + * class associates a single boolean with a reference. For example, this
58.169 + * bit might be used inside a data structure to mean that the object
58.170 + * being referenced has logically been deleted.
58.171 + *
58.172 + * The {@link java.util.concurrent.atomic.AtomicStampedReference}
58.173 + * class associates an integer value with a reference. This may be
58.174 + * used for example, to represent version numbers corresponding to
58.175 + * series of updates.
58.176 + *
58.177 + * <p>Atomic classes are designed primarily as building blocks for
58.178 + * implementing non-blocking data structures and related infrastructure
58.179 + * classes. The {@code compareAndSet} method is not a general
58.180 + * replacement for locking. It applies only when critical updates for an
58.181 + * object are confined to a <em>single</em> variable.
58.182 + *
58.183 + * <p>Atomic classes are not general purpose replacements for
58.184 + * {@code java.lang.Integer} and related classes. They do <em>not</em>
58.185 + * define methods such as {@code hashCode} and
58.186 + * {@code compareTo}. (Because atomic variables are expected to be
58.187 + * mutated, they are poor choices for hash table keys.) Additionally,
58.188 + * classes are provided only for those types that are commonly useful in
58.189 + * intended applications. For example, there is no atomic class for
58.190 + * representing {@code byte}. In those infrequent cases where you would
58.191 + * like to do so, you can use an {@code AtomicInteger} to hold
58.192 + * {@code byte} values, and cast appropriately.
58.193 + *
58.194 + * You can also hold floats using
58.195 + * {@link java.lang.Float#floatToIntBits} and
58.196 + * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
58.197 + * {@link java.lang.Double#doubleToLongBits} and
58.198 + * {@link java.lang.Double#longBitsToDouble} conversions.
58.199 + *
58.200 + * @since 1.5
58.201 + */
58.202 +package java.util.concurrent.atomic;