summaryrefslogtreecommitdiff
path: root/libjava/classpath/java
diff options
context:
space:
mode:
authordoko <doko@138bc75d-0d04-0410-961f-82ee72b054a4>2007-06-03 23:18:43 +0000
committerdoko <doko@138bc75d-0d04-0410-961f-82ee72b054a4>2007-06-03 23:18:43 +0000
commit5bf762459121cc397663d22498d62d71fa179ef6 (patch)
treea9c9e7d91c484d53fe154f9285fc57325572ce50 /libjava/classpath/java
parent6d7301dc346a198a89ac987c1008aac09f191ee6 (diff)
downloadgcc-5bf762459121cc397663d22498d62d71fa179ef6.tar.gz
libjava/classpath/ChangeLog.gcj:
2007-05-31 Matthias Klose <doko@ubuntu.com> * javax/management/NotificationBroadcasterSupport.java (getNotificationInfo): Add cast. * native/jni/qt-peer/Makefile.am (AM_CXXFLAGS): Add libstdc++ include directories. * native/jni/qt-peer/Makefile.in: Regenerate. libjava/ChangeLog: 2007-06-03 Matthias Klose <doko@ubuntu.com> * java/io/natFileWin32.cc (setFilePermissions): New (stub only). _access: Handle EXEC query, stub only. 2007-06-03 Matthias Klose <doko@ubuntu.com> Merged from classpath: * gnu/java/nio/SelectorProviderImpl.java: Whitespace merge. * java/lang/System.java(inheritedChannel): New. * java/lang/Character.java: Remove stray`;'. * java/net/MulticastSocket.java: Merged. * java/text/DateFormatSymbols.java(getInstance): New, comment updates. * java/text/Collator.java(getInstance): Merged. * java/util/Calendar.java: New attributes ALL_STYLES, SHORT, LONG. getDisplayName, getDisplayNames: New. * java/util/logging/Logger.java: Merged. * Regenerate .class and .h files. 2007-06-03 Matthias Klose <doko@ubuntu.com> * java/io/File.java: Merge with classpath-0.95, new method setFilePermissions, new attribute EXEC. * java/io/natFilePosix.cc (setFilePermissions): New. _access: Handle EXEC query. * classpath/lib/java/io/File.class, java/io/File.h: Regenerate. 2007-06-03 Matthias Klose <doko@ubuntu.com> Imported GNU Classpath 0.95. * classpath/Makefile.in, classpath/native/jni/midi-dssi/Makefile.in, classpath/native/jni/classpath/Makefile.in, classpath/native/jni/Makefile.in, classpath/native/jni/gconf-peer/Makefile.in, classpath/native/jni/java-io/Makefile.in, classpath/native/jni/native-lib/Makefile.in, classpath/native/jni/java-util/Makefile.in, classpath/native/jni/midi-alsa/Makefile.in, classpath/native/jni/java-lang/Makefile.in, classpath/native/jni/java-nio/Makefile.in, classpath/native/jni/java-net/Makefile.in, classpath/native/jni/xmlj/Makefile.in, classpath/native/jni/qt-peer/Makefile.in, classpath/native/jni/gtk-peer/Makefile.in, classpath/native/Makefile.in, classpath/native/jawt/Makefile.in, classpath/native/fdlibm/Makefile.in, classpath/native/plugin/Makefile.in, classpath/resource/Makefile.in, classpath/scripts/Makefile.in, classpath/tools/Makefile.in, classpath/doc/Makefile.in, classpath/doc/api/Makefile.in, classpath/lib/Makefile.in, classpath/external/Makefile.in, classpath/external/jsr166/Makefile.in, classpath/external/sax/Makefile.in, classpath/external/w3c_dom/Makefile.in, classpath/external/relaxngDatatype/Makefile.in, classpath/include/Makefile.in, classpath/examples/Makefile.in: Regenerate. * classpath/config.guess, classpath/config.sub, classpath/ltmain.sh : Update. * classpath/configure, classpath/depcomp, classpath/missing, classpath/aclocal.m4, classpath/install-sh: Regenerate. * gnu/classpath/Configuration.java (CLASSPATH_VERSION): Now 0.95. * sources.am: Regenerate. * Makefile.in: Regenerate. * Update the .class files and generated CNI header files, add new .class and generated CNI header files. * Remove generated files for removed java source files: classpath/gnu/java/net/BASE64.java, classpath/gnu/java/security/util/Base64.java, classpath/gnu/java/awt/peer/gtk/GThreadMutex.java, classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java, classpath/gnu/java/awt/font/autofit/Scaler.java, classpath/gnu/classpath/jdwp/util/Value.java, classpath/gnu/javax/net/ssl/Base64.java. * Remove empty directories. * Makefile.am(nat_source_files): Add natVMOperatingSystemMXBeanImpl.cc. * java/lang/Class.java(setAccessible): Merge from classpath. * java/util/Locale.java: Remove. * gnu/java/lang/management/VMOperatingSystemMXBeanImpl.java, gnu/java/lang/management/natVMOperatingSystemMXBeanImpl.cc: New. * gcj/javaprims.h: Update class declarations. * scripts/classes.pl: Update usage. * HACKING: Mention to build all peers. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@125302 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/java')
-rw-r--r--libjava/classpath/java/awt/AWTEvent.java12
-rw-r--r--libjava/classpath/java/awt/AWTKeyStroke.java6
-rw-r--r--libjava/classpath/java/awt/AlphaComposite.java6
-rw-r--r--libjava/classpath/java/awt/Canvas.java14
-rw-r--r--libjava/classpath/java/awt/CardLayout.java2
-rw-r--r--libjava/classpath/java/awt/Component.java60
-rw-r--r--libjava/classpath/java/awt/Desktop.java268
-rw-r--r--libjava/classpath/java/awt/EventDispatchThread.java3
-rw-r--r--libjava/classpath/java/awt/EventQueue.java6
-rw-r--r--libjava/classpath/java/awt/Frame.java85
-rw-r--r--libjava/classpath/java/awt/GraphicsConfiguration.java31
-rw-r--r--libjava/classpath/java/awt/RenderingHints.java10
-rw-r--r--libjava/classpath/java/awt/Toolkit.java24
-rw-r--r--libjava/classpath/java/awt/Window.java32
-rw-r--r--libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java154
-rw-r--r--libjava/classpath/java/awt/geom/GeneralPath.java11
-rw-r--r--libjava/classpath/java/awt/image/BufferedImage.java327
-rw-r--r--libjava/classpath/java/awt/image/ComponentSampleModel.java448
-rw-r--r--libjava/classpath/java/awt/image/IndexColorModel.java17
-rw-r--r--libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java150
-rw-r--r--libjava/classpath/java/awt/peer/DesktopPeer.java64
-rw-r--r--libjava/classpath/java/awt/print/PrinterJob.java15
-rw-r--r--libjava/classpath/java/beans/ConstructorProperties.java72
-rw-r--r--libjava/classpath/java/beans/XMLEncoder.java2
-rw-r--r--libjava/classpath/java/io/File.java179
-rw-r--r--libjava/classpath/java/io/ObjectInputStream.java175
-rw-r--r--libjava/classpath/java/io/ObjectOutputStream.java88
-rw-r--r--libjava/classpath/java/io/StreamTokenizer.java2
-rw-r--r--libjava/classpath/java/io/class-dependencies.conf100
-rw-r--r--libjava/classpath/java/lang/Character.java2
-rw-r--r--libjava/classpath/java/lang/Class.java30
-rw-r--r--libjava/classpath/java/lang/Enum.java13
-rw-r--r--libjava/classpath/java/lang/StrictMath.java5
-rw-r--r--libjava/classpath/java/lang/String.java17
-rw-r--r--libjava/classpath/java/lang/System.java25
-rw-r--r--libjava/classpath/java/lang/class-dependencies.conf58
-rw-r--r--libjava/classpath/java/lang/management/LockInfo.java114
-rw-r--r--libjava/classpath/java/lang/management/ManagementFactory.java265
-rw-r--r--libjava/classpath/java/lang/management/MemoryUsage.java16
-rw-r--r--libjava/classpath/java/lang/management/MonitorInfo.java179
-rw-r--r--libjava/classpath/java/lang/management/OperatingSystemMXBean.java16
-rw-r--r--libjava/classpath/java/lang/management/ThreadInfo.java431
-rw-r--r--libjava/classpath/java/lang/management/ThreadMXBean.java167
-rw-r--r--libjava/classpath/java/math/BigInteger.java5
-rw-r--r--libjava/classpath/java/math/class-dependencies.conf58
-rw-r--r--libjava/classpath/java/net/MimeTypeMapper.java13
-rw-r--r--libjava/classpath/java/net/MulticastSocket.java6
-rw-r--r--libjava/classpath/java/net/NetworkInterface.java7
-rw-r--r--libjava/classpath/java/net/Proxy.java2
-rw-r--r--libjava/classpath/java/net/ResolverCache.java4
-rw-r--r--libjava/classpath/java/net/ServerSocket.java7
-rw-r--r--libjava/classpath/java/net/Socket.java23
-rw-r--r--libjava/classpath/java/net/URI.java2
-rw-r--r--libjava/classpath/java/net/URL.java11
-rw-r--r--libjava/classpath/java/net/URLClassLoader.java29
-rw-r--r--libjava/classpath/java/net/class-dependencies.conf122
-rw-r--r--libjava/classpath/java/nio/ByteOrder.java4
-rw-r--r--libjava/classpath/java/nio/channels/spi/SelectorProvider.java27
-rw-r--r--libjava/classpath/java/nio/class-dependencies.conf58
-rw-r--r--libjava/classpath/java/rmi/activation/ActivationID.java2
-rw-r--r--libjava/classpath/java/rmi/server/UnicastRemoteObject.java5
-rw-r--r--libjava/classpath/java/security/BasicPermission.java3
-rw-r--r--libjava/classpath/java/security/Permission.java17
-rw-r--r--libjava/classpath/java/security/SecureClassLoader.java2
-rw-r--r--libjava/classpath/java/security/SignatureSpi.java13
-rw-r--r--libjava/classpath/java/security/cert/X509CertSelector.java1419
-rw-r--r--libjava/classpath/java/security/cert/X509Certificate.java4
-rw-r--r--libjava/classpath/java/text/AttributedStringIterator.java8
-rw-r--r--libjava/classpath/java/text/BreakIterator.java117
-rw-r--r--libjava/classpath/java/text/Collator.java50
-rw-r--r--libjava/classpath/java/text/DateFormat.java148
-rw-r--r--libjava/classpath/java/text/DateFormatSymbols.java159
-rw-r--r--libjava/classpath/java/text/DecimalFormat.java31
-rw-r--r--libjava/classpath/java/text/DecimalFormatSymbols.java89
-rw-r--r--libjava/classpath/java/text/MessageFormat.java128
-rw-r--r--libjava/classpath/java/text/NumberFormat.java135
-rw-r--r--libjava/classpath/java/text/SimpleDateFormat.java16
-rw-r--r--libjava/classpath/java/text/class-dependencies.conf220
-rw-r--r--libjava/classpath/java/text/spi/BreakIteratorProvider.java124
-rw-r--r--libjava/classpath/java/text/spi/CollatorProvider.java79
-rw-r--r--libjava/classpath/java/text/spi/DateFormatProvider.java129
-rw-r--r--libjava/classpath/java/text/spi/DateFormatSymbolsProvider.java79
-rw-r--r--libjava/classpath/java/text/spi/DecimalFormatSymbolsProvider.java79
-rw-r--r--libjava/classpath/java/text/spi/NumberFormatProvider.java129
-rw-r--r--libjava/classpath/java/text/spi/package.html50
-rw-r--r--libjava/classpath/java/util/AbstractMap.java29
-rw-r--r--libjava/classpath/java/util/Arrays.java998
-rw-r--r--libjava/classpath/java/util/Calendar.java250
-rw-r--r--libjava/classpath/java/util/Collections.java217
-rw-r--r--libjava/classpath/java/util/Currency.java33
-rw-r--r--libjava/classpath/java/util/Date.java2
-rw-r--r--libjava/classpath/java/util/GregorianCalendar.java18
-rw-r--r--libjava/classpath/java/util/HashMap.java16
-rw-r--r--libjava/classpath/java/util/Hashtable.java18
-rw-r--r--libjava/classpath/java/util/LinkedList.java271
-rw-r--r--libjava/classpath/java/util/Locale.java76
-rw-r--r--libjava/classpath/java/util/PriorityQueue.java1
-rw-r--r--libjava/classpath/java/util/ServiceConfigurationError.java94
-rw-r--r--libjava/classpath/java/util/ServiceLoader.java274
-rw-r--r--libjava/classpath/java/util/StringTokenizer.java8
-rw-r--r--libjava/classpath/java/util/TreeMap.java1970
-rw-r--r--libjava/classpath/java/util/TreeSet.java244
-rw-r--r--libjava/classpath/java/util/class-dependencies.conf78
-rw-r--r--libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java3
-rw-r--r--libjava/classpath/java/util/logging/LogManager.java16
-rw-r--r--libjava/classpath/java/util/logging/Logger.java18
-rw-r--r--libjava/classpath/java/util/prefs/AbstractPreferences.java17
-rw-r--r--libjava/classpath/java/util/prefs/Preferences.java6
-rw-r--r--libjava/classpath/java/util/regex/Pattern.java14
-rw-r--r--libjava/classpath/java/util/spi/CurrencyNameProvider.java100
-rw-r--r--libjava/classpath/java/util/spi/LocaleNameProvider.java135
-rw-r--r--libjava/classpath/java/util/spi/LocaleServiceProvider.java125
-rw-r--r--libjava/classpath/java/util/spi/TimeZoneNameProvider.java97
-rw-r--r--libjava/classpath/java/util/spi/package.html50
-rw-r--r--libjava/classpath/java/util/zip/DeflaterEngine.java3
-rw-r--r--libjava/classpath/java/util/zip/ZipInputStream.java1
116 files changed, 9783 insertions, 2713 deletions
diff --git a/libjava/classpath/java/awt/AWTEvent.java b/libjava/classpath/java/awt/AWTEvent.java
index 3f4027c2c05..102062cdfe6 100644
--- a/libjava/classpath/java/awt/AWTEvent.java
+++ b/libjava/classpath/java/awt/AWTEvent.java
@@ -262,9 +262,17 @@ public abstract class AWTEvent extends EventObject
*/
public String toString ()
{
+ String src;
+ if (source instanceof Component)
+ src = ((Component) source).getName();
+ else if (source instanceof MenuComponent)
+ src = ((MenuComponent) source).getName();
+ else if (source != null)
+ src = source.toString();
+ else
+ src = "null";
String string = getClass ().getName () + "[" + paramString () + "] on "
- + source;
-
+ + src;
return string;
}
diff --git a/libjava/classpath/java/awt/AWTKeyStroke.java b/libjava/classpath/java/awt/AWTKeyStroke.java
index 527e85873e0..e0b34e99238 100644
--- a/libjava/classpath/java/awt/AWTKeyStroke.java
+++ b/libjava/classpath/java/awt/AWTKeyStroke.java
@@ -1,5 +1,5 @@
/* AWTKeyStroke.java -- an immutable key stroke
- Copyright (C) 2002, 2004, 2005 Free Software Foundation
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation
This file is part of GNU Classpath.
@@ -93,9 +93,9 @@ public class AWTKeyStroke implements Serializable
private static final int MAX_CACHE_SIZE = 2048;
/** Prune stale entries. */
- protected boolean removeEldestEntry(Map.Entry<AWTKeyStroke,AWTKeyStroke>
+ protected boolean removeEldestEntry(Entry<AWTKeyStroke,AWTKeyStroke>
eldest)
- { // XXX - FIXME Use Map.Entry, not just Entry as gcj 3.1 workaround.
+ {
return size() > MAX_CACHE_SIZE;
}
};
diff --git a/libjava/classpath/java/awt/AlphaComposite.java b/libjava/classpath/java/awt/AlphaComposite.java
index 92b9e09a60d..90df2e66d8c 100644
--- a/libjava/classpath/java/awt/AlphaComposite.java
+++ b/libjava/classpath/java/awt/AlphaComposite.java
@@ -1,5 +1,5 @@
/* AlphaComposite.java -- provides a context for performing alpha compositing
- Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -61,8 +61,8 @@ public final class AlphaComposite implements Composite
private static final int MAX_CACHE_SIZE = 2048;
/** Prune stale entries. */
- protected boolean removeEldestEntry(Map.Entry eldest)
- { // XXX - FIXME Use Map.Entry, not just Entry as gcj 3.1 workaround.
+ protected boolean removeEldestEntry(Entry eldest)
+ {
return size() > MAX_CACHE_SIZE;
}
};
diff --git a/libjava/classpath/java/awt/Canvas.java b/libjava/classpath/java/awt/Canvas.java
index 843fded44db..95db1f57e1a 100644
--- a/libjava/classpath/java/awt/Canvas.java
+++ b/libjava/classpath/java/awt/Canvas.java
@@ -75,11 +75,6 @@ public class Canvas
private static transient long next_canvas_number;
/**
- * The graphics configuration associated with the canvas.
- */
- transient GraphicsConfiguration graphicsConfiguration;
-
- /**
* The buffer strategy associated with this canvas.
*/
transient BufferStrategy bufferStrategy;
@@ -100,14 +95,7 @@ public class Canvas
*/
public Canvas(GraphicsConfiguration graphicsConfiguration)
{
- this.graphicsConfiguration = graphicsConfiguration;
- }
-
- GraphicsConfiguration getGraphicsConfigurationImpl()
- {
- if (graphicsConfiguration != null)
- return graphicsConfiguration;
- return super.getGraphicsConfigurationImpl();
+ this.graphicsConfig = graphicsConfiguration;
}
/**
diff --git a/libjava/classpath/java/awt/CardLayout.java b/libjava/classpath/java/awt/CardLayout.java
index 2e3feece8d2..35380d2370b 100644
--- a/libjava/classpath/java/awt/CardLayout.java
+++ b/libjava/classpath/java/awt/CardLayout.java
@@ -225,7 +225,7 @@ public class CardLayout implements LayoutManager2, Serializable
*/
public Dimension maximumLayoutSize (Container target)
{
- if (target == null)
+ if (target == null || target.ncomponents == 0)
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
// The JCL says that this returns Integer.MAX_VALUE for both
// dimensions. But that just seems wrong to me.
diff --git a/libjava/classpath/java/awt/Component.java b/libjava/classpath/java/awt/Component.java
index b6eadabbb5c..f8bed17618e 100644
--- a/libjava/classpath/java/awt/Component.java
+++ b/libjava/classpath/java/awt/Component.java
@@ -726,7 +726,23 @@ public abstract class Component
*/
public GraphicsConfiguration getGraphicsConfiguration()
{
- return getGraphicsConfigurationImpl();
+ GraphicsConfiguration conf = null;
+ synchronized (getTreeLock())
+ {
+ if (graphicsConfig != null)
+ {
+ conf = graphicsConfig;
+ }
+ else
+ {
+ Component par = getParent();
+ if (par != null)
+ {
+ conf = parent.getGraphicsConfiguration();
+ }
+ }
+ }
+ return conf;
}
/**
@@ -823,7 +839,8 @@ public abstract class Component
*/
public boolean isShowing()
{
- return visible && peer != null && (parent == null || parent.isShowing());
+ Component par = parent;
+ return visible && peer != null && (par == null || par.isShowing());
}
/**
@@ -1179,19 +1196,12 @@ public abstract class Component
*/
public Font getFont()
{
- Font f;
- synchronized (getTreeLock())
- {
- f = getFontImpl();
- }
- return f;
+ return getFontImpl();
}
/**
* Implementation of getFont(). This is pulled out of getFont() to prevent
- * client programs from overriding this. This method is executed within
- * a tree lock, so we can assume that the hierarchy doesn't change in
- * between.
+ * client programs from overriding this.
*
* @return the font of this component
*/
@@ -1204,7 +1214,12 @@ public abstract class Component
if (p != null)
f = p.getFontImpl();
else
- f = new Font("Dialog", Font.PLAIN, 12);
+ {
+ // It is important to return null here and not some kind of default
+ // font, otherwise the Swing UI would not install its fonts because
+ // it keeps non-UIResource fonts.
+ f = null;
+ }
}
return f;
}
@@ -5435,27 +5450,6 @@ p * <li>the set of backward traversal keys
}
/**
- * Implementation method that allows classes such as Canvas and Window to
- * override the graphics configuration without violating the published API.
- *
- * @return the graphics configuration
- */
- GraphicsConfiguration getGraphicsConfigurationImpl()
- {
- if (peer != null)
- {
- GraphicsConfiguration config = peer.getGraphicsConfiguration();
- if (config != null)
- return config;
- }
-
- if (parent != null)
- return parent.getGraphicsConfiguration();
-
- return null;
- }
-
- /**
* Translate an AWT 1.1 event ({@link AWTEvent}) into an AWT 1.0
* event ({@link Event}).
*
diff --git a/libjava/classpath/java/awt/Desktop.java b/libjava/classpath/java/awt/Desktop.java
new file mode 100644
index 00000000000..8010464c00d
--- /dev/null
+++ b/libjava/classpath/java/awt/Desktop.java
@@ -0,0 +1,268 @@
+/* Desktop.java -- enable desktop integration between java programs and system
+ programs.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package java.awt;
+
+import java.awt.peer.DesktopPeer;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * This class enables Java application to access system commands to perform
+ * desktop oriented operations, like writing and sending emails, or surfing
+ * webpages with the system browser or editing/printing files with a default
+ * editor. Methods are provided to handle these common operations, plus an
+ * <code>open</code> command selects a default registered application for the
+ * specified file type. For example, opening an odf file results in launching
+ * OpenOffice. If an operation is not supported, or the application fails to
+ * launch, an exception is generated.
+ *
+ * <strong>Implementation note: </strong>As this class is used to manage Desktop
+ * integration, we provide some extension to configure the behaviour of this
+ * class depending on the type of dektop that is detected.<br />
+ *
+ * First of all, we support 5 system properties that can be used to define
+ * the application to launch in any given case. These properties are:<br />
+ * <br />
+ * <code>gnu.java.awt.peer.Desktop.html.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.mail.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.edit.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.print.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.open.command</code><br />
+ * <br />
+ * <br />
+ * These can be specified from the command line and have priority on every
+ * other setting.<br />
+ * <br />
+ * The second method supported is defining a Java preference.<br />
+ * The main preference node is a <strong>user node</strong> relative to the
+ * class <code>gnu.java.awt.peer.ClasspathDesktopPeer</code>. This node
+ * contains a child for each supported operation. The key for each type is
+ * always <code>command</code>:
+ * <br /><br />
+ * <code>gnu.java.awt.peer.Desktop.html.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.mail.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.edit.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.print.command</code><br />
+ * <code>gnu.java.awt.peer.Desktop.open.command</code><br />
+ * <br />
+ * <br />
+ * The access to these keys is done with the Preference API or, if outside
+ * of the java scope, is done in a backend dependent way. For example,
+ * with the GConf backend, you can access these properties
+ * with (may not be accurate on your system):
+ * <br /><br />
+ * <code>
+ * gconftool-2 -g /apps/classpath/gnu/java/awt/peer/Desktop/html/command
+ * </code>
+ *
+ * @author Mario Torre <neugens@limasoftware.net>
+ * @since 1.6
+ */
+public class Desktop
+{
+ /**
+ * Represents an action type supported by a platform.
+ *
+ * To determine if a given action is supported by the platform,
+ * use the <code>Desktop.isSupported(java.awt.Desktop.Action)</code>
+ * method.
+ *
+ * @author Mario Torre <neugens@limasoftware.net>
+ */
+ public enum Action
+ {
+ BROWSE, EDIT, MAIL, OPEN, PRINT
+ }
+
+ private DesktopPeer peer;
+
+ private Desktop()
+ {
+ /* nothing to be done */
+ }
+
+ /**
+ * Returns an istance of the Desktop Class.
+ *
+ * If this implementation does not support Desktop, an
+ * UnsupportedOperationException will be thrown.
+ * Also, an HeadlessException will be generated if
+ * GraphicsEnvironment.isHeadless() returns true.
+ *
+ * @throws UnsupportedOperationException
+ * @throws HeadlessException
+ */
+ public static Desktop getDesktop() throws UnsupportedOperationException,
+ HeadlessException
+ {
+ if (GraphicsEnvironment.isHeadless())
+ throw new HeadlessException();
+
+ if (!Desktop.isDesktopSupported())
+ throw new UnsupportedOperationException();
+
+ Desktop desktop = new Desktop();
+ desktop.peer = Toolkit.getDefaultToolkit().createDesktopPeer(desktop);
+
+ return desktop;
+ }
+
+ /**
+ * Check if this implementation supports Desktop.
+ * If true, use getDesktop to get an instance of this class.
+ *
+ * This implementation will return false when GraphicsEnvironment.isHeadless
+ * returns true.
+ *
+ * @return true if this class is supported on the current platform;
+ * false otherwise
+ */
+ private static boolean isDesktopSupported()
+ {
+ if (GraphicsEnvironment.isHeadless())
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Check if the given Action is supported by this implementation.
+ *
+ * @param action
+ * @return
+ */
+ public boolean isSupported(Desktop.Action action)
+ {
+ return peer.isSupported(action);
+ }
+
+ /**
+ * Launches the Desktop default browser to open the given <code>uri</code>.
+ *
+ * If a security manager exists and denies
+ * AWTPermission("showWindowWithoutWarningBanner"),a SecurityException will
+ * be generated.
+ *
+ * @param uri
+ * @throws IOException
+ */
+ public void browse(URI uri)
+ throws IOException
+ {
+ peer.browse(uri);
+ }
+
+ /**
+ * Launch the edit command to edit this file.
+ * File should already exist before the editing starts.
+ *
+ * If a security manager exists and
+ * SecurityManager.checkRead(java.lang.String) method denies read access to
+ * the file, or SecurityManager.checkPrintJobAccess() method denies the
+ * permission to print the file, a SecurityException will be generated.
+ *
+ * @param file
+ * @throws IOException
+ */
+ public void edit(File file)
+ throws IOException
+ {
+ peer.edit(file);
+ }
+
+ /**
+ * Launches the Desktop default mailer.
+ *
+ * If a security manager exists and denies
+ * AWTPermission("showWindowWithoutWarningBanner"), a SecurityException will
+ * be generated.
+ *
+ * @throws IOException
+ */
+ public void mail()
+ throws IOException
+ {
+ peer.mail();
+ }
+
+ /**
+ * Launches the Desktop default mailer, with the given mailtoURI
+ * as agrument. The <code>mailtoURI</code> must conform to the
+ * {@link http://www.ietf.org/rfc/rfc2368.txt The mailto URL scheme (RFC 2368)}
+ *
+ * If a security manager exists and denies
+ * AWTPermission("showWindowWithoutWarningBanner"), a SecurityException will
+ * be generated.
+ *
+ * @param mailtoURI
+ * @throws IOException
+ */
+ public void mail(URI mailtoURI)
+ throws IOException
+ {
+ peer.mail(mailtoURI);
+ }
+
+ /**
+ * Launches the Desktop default application to open the given File.
+ * If <code>file</code> is a directory, a file manager is launched.
+ *
+ * @param file
+ * @throws IOException
+ */
+ public void open(File file)
+ throws IOException
+ {
+ peer.open(file);
+ }
+
+ /**
+ * Launch the print program to print this file.
+ *
+ * @param file
+ * @throws IOException
+ */
+ public void print(File file)
+ throws IOException
+ {
+ peer.print(file);
+ }
+}
diff --git a/libjava/classpath/java/awt/EventDispatchThread.java b/libjava/classpath/java/awt/EventDispatchThread.java
index 074a84975ac..9f81a794415 100644
--- a/libjava/classpath/java/awt/EventDispatchThread.java
+++ b/libjava/classpath/java/awt/EventDispatchThread.java
@@ -73,6 +73,9 @@ class EventDispatchThread extends Thread
// Ignore and use default.
}
setPriority(priority);
+
+ // Make sure that an event dispatch thread is never a daemon thread.
+ setDaemon(false);
}
public void run()
diff --git a/libjava/classpath/java/awt/EventQueue.java b/libjava/classpath/java/awt/EventQueue.java
index 74dbd5fb67d..eb17449a00c 100644
--- a/libjava/classpath/java/awt/EventQueue.java
+++ b/libjava/classpath/java/awt/EventQueue.java
@@ -128,10 +128,8 @@ public class EventQueue
if (peekEvent() != null)
return false;
- Frame[] frames = Frame.getFrames();
- for (int i = 0; i < frames.length; ++i)
- if (frames[i].isDisplayable())
- return false;
+ if (Frame.hasDisplayableFrames())
+ return false;
return true;
}
diff --git a/libjava/classpath/java/awt/Frame.java b/libjava/classpath/java/awt/Frame.java
index d5cc7f53197..3cc8738c63f 100644
--- a/libjava/classpath/java/awt/Frame.java
+++ b/libjava/classpath/java/awt/Frame.java
@@ -40,9 +40,10 @@ exception statement from your version. */
package java.awt;
import java.awt.peer.FramePeer;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.Vector;
import javax.accessibility.AccessibleContext;
@@ -484,44 +485,72 @@ public class Frame extends Window implements MenuContainer
return super.paramString () + ",title=" + title + resizable + state;
}
- private static ArrayList weakFrames = new ArrayList();
+ /**
+ * The list of active frames. GC'ed frames get removed in noteFrame().
+ */
+ private static ArrayList<WeakReference<Frame>> weakFrames =
+ new ArrayList<WeakReference<Frame>>();
+
+ /**
+ * The death queue for all frames.
+ */
+ private static ReferenceQueue weakFramesQueue =
+ new ReferenceQueue<Frame>();
private static void noteFrame(Frame f)
{
synchronized (weakFrames)
{
- weakFrames.add(new WeakReference(f));
+ // Remove GCed frames from the list.
+ Reference ref = weakFramesQueue.poll();
+ while (ref != null)
+ {
+ weakFrames.remove(ref);
+ ref = weakFramesQueue.poll();
+ }
+ // Add new frame.
+ weakFrames.add(new WeakReference<Frame>(f));
}
}
+ /**
+ * Returns <code>true</code> when there are any displayable frames,
+ * <code>false</code> otherwise.
+ *
+ * @return <code>true</code> when there are any displayable frames,
+ * <code>false</code> otherwise
+ */
+ static boolean hasDisplayableFrames()
+ {
+ synchronized (weakFrames)
+ {
+ for (WeakReference<Frame> r : Frame.weakFrames)
+ {
+ Frame f = (Frame) r.get();
+ if (f != null && f.isDisplayable())
+ return true;
+ }
+ }
+ return false;
+ }
+
public static Frame[] getFrames()
{
- int n = 0;
synchronized (weakFrames)
- {
- Iterator i = weakFrames.iterator();
- while (i.hasNext())
- {
- WeakReference wr = (WeakReference) i.next();
- if (wr.get() != null)
- ++n;
- }
- if (n == 0)
- return new Frame[0];
- else
- {
- Frame[] frames = new Frame[n];
- n = 0;
- i = weakFrames.iterator();
- while (i.hasNext())
- {
- WeakReference wr = (WeakReference) i.next();
- if (wr.get() != null)
- frames[n++] = (Frame) wr.get();
- }
- return frames;
- }
- }
+ {
+ ArrayList<Frame> existingFrames = new ArrayList<Frame>();
+ for (WeakReference<Frame> ref : weakFrames)
+ {
+ Frame f = ref.get();
+ if (f != null)
+ {
+ existingFrames.add(f);
+ }
+ }
+ Frame[] frames = new Frame[existingFrames.size()];
+ frames = existingFrames.toArray(frames);
+ return frames;
+ }
}
public void setState(int state)
diff --git a/libjava/classpath/java/awt/GraphicsConfiguration.java b/libjava/classpath/java/awt/GraphicsConfiguration.java
index 792b2cc1b2b..3cf8b65db8f 100644
--- a/libjava/classpath/java/awt/GraphicsConfiguration.java
+++ b/libjava/classpath/java/awt/GraphicsConfiguration.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package java.awt;
-import gnu.classpath.NotImplementedException;
-
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
@@ -131,7 +129,8 @@ public abstract class GraphicsConfiguration
ImageCapabilities caps)
throws AWTException
{
- throw new AWTException("not implemented");
+ // Must be overridden by implementations to check caps.
+ return createCompatibleVolatileImage(w, h);
}
/**
@@ -150,6 +149,32 @@ public abstract class GraphicsConfiguration
int transparency);
/**
+ * Creates a volatile image with the specified capabilities and transparency.
+ * If the backend cannot meet the requested capabilities and transparency,
+ * an AWTException is thrown.
+ *
+ * @param width the width of the image
+ * @param height the height of the image
+ * @param caps the requested capabilities
+ * @param transparency the required transparency
+ *
+ * @return a volatile image with the specified capabilites and transparency
+ *
+ * @throws AWTException if the required capabilities and transparency cannot
+ * be met
+ *
+ * @since 1.5
+ */
+ public VolatileImage createCompatibleVolatileImage(int width, int height,
+ ImageCapabilities caps,
+ int transparency)
+ throws AWTException
+ {
+ // Must be overridden by implementations to check caps.
+ return createCompatibleVolatileImage(width, height, transparency);
+ }
+
+ /**
* Returns a buffered image optimized to this device, and with the specified
* transparency, so that blitting can be supported in the buffered image.
*
diff --git a/libjava/classpath/java/awt/RenderingHints.java b/libjava/classpath/java/awt/RenderingHints.java
index ce327e36947..e98a00c5bab 100644
--- a/libjava/classpath/java/awt/RenderingHints.java
+++ b/libjava/classpath/java/awt/RenderingHints.java
@@ -158,7 +158,7 @@ public class RenderingHints
}
} // class KeyImpl
- private HashMap hintMap = new HashMap();
+ private HashMap<Object,Object> hintMap = new HashMap<Object,Object>();
/**
* A key for the 'antialiasing' hint. Permitted values are:
@@ -711,9 +711,9 @@ public class RenderingHints
Iterator iterator = m.keySet().iterator();
while (iterator.hasNext())
{
- Key key = (Key) iterator.next();
- if (!key.isCompatibleValue(m.get(key)))
- throw new IllegalArgumentException();
+ Key key = (Key) iterator.next();
+ if (!key.isCompatibleValue(m.get(key)))
+ throw new IllegalArgumentException();
}
// map is OK, update
hintMap.putAll(m);
@@ -783,7 +783,7 @@ public class RenderingHints
try
{
RenderingHints copy = (RenderingHints) super.clone();
- copy.hintMap = (HashMap) hintMap.clone();
+ copy.hintMap = new HashMap<Object,Object>(hintMap);
return copy;
}
catch (CloneNotSupportedException e)
diff --git a/libjava/classpath/java/awt/Toolkit.java b/libjava/classpath/java/awt/Toolkit.java
index 69040722e72..305402e9541 100644
--- a/libjava/classpath/java/awt/Toolkit.java
+++ b/libjava/classpath/java/awt/Toolkit.java
@@ -1,5 +1,5 @@
/* Toolkit.java -- AWT Toolkit superclass
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,6 +40,7 @@ exception statement from your version. */
package java.awt;
import gnu.classpath.SystemProperties;
+import gnu.java.awt.AWTUtilities;
import gnu.java.awt.peer.GLightweightPeer;
import gnu.java.awt.peer.headless.HeadlessToolkit;
@@ -62,6 +63,7 @@ import java.awt.peer.CanvasPeer;
import java.awt.peer.CheckboxMenuItemPeer;
import java.awt.peer.CheckboxPeer;
import java.awt.peer.ChoicePeer;
+import java.awt.peer.DesktopPeer;
import java.awt.peer.DialogPeer;
import java.awt.peer.FileDialogPeer;
import java.awt.peer.FontPeer;
@@ -148,6 +150,15 @@ public abstract class Toolkit
}
/**
+ *
+ * @param target
+ * @return
+ * @throws HeadlessException
+ */
+ protected abstract DesktopPeer createDesktopPeer(Desktop target)
+ throws HeadlessException;
+
+ /**
* Creates a peer object for the specified <code>Button</code>.
*
* @param target The <code>Button</code> to create the peer for.
@@ -802,12 +813,11 @@ public abstract class Toolkit
*/
public boolean getLockingKeyState(int keyCode)
{
- if (keyCode != KeyEvent.VK_CAPS_LOCK
- && keyCode != KeyEvent.VK_NUM_LOCK
- && keyCode != KeyEvent.VK_SCROLL_LOCK)
- throw new IllegalArgumentException();
-
- throw new UnsupportedOperationException();
+ if (AWTUtilities.isValidKey(keyCode))
+ throw new UnsupportedOperationException
+ ("cannot get locking state of key code " + keyCode);
+
+ throw new IllegalArgumentException("invalid key code " + keyCode);
}
/**
diff --git a/libjava/classpath/java/awt/Window.java b/libjava/classpath/java/awt/Window.java
index 41dff5577e0..2a59375ced9 100644
--- a/libjava/classpath/java/awt/Window.java
+++ b/libjava/classpath/java/awt/Window.java
@@ -87,7 +87,6 @@ public class Window extends Container implements Accessible
private transient WindowListener windowListener;
private transient WindowFocusListener windowFocusListener;
private transient WindowStateListener windowStateListener;
- private transient GraphicsConfiguration graphicsConfiguration;
private transient boolean shown;
@@ -132,13 +131,13 @@ public class Window extends Container implements Accessible
setLayout(new BorderLayout());
GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment();
- graphicsConfiguration = g.getDefaultScreenDevice().getDefaultConfiguration();
+ graphicsConfig = g.getDefaultScreenDevice().getDefaultConfiguration();
}
Window(GraphicsConfiguration gc)
{
this();
- graphicsConfiguration = gc;
+ graphicsConfig = gc;
}
/**
@@ -204,19 +203,11 @@ public class Window extends Container implements Accessible
throw new IllegalArgumentException ("gc must be from a screen device");
if (gc == null)
- graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment()
- .getDefaultScreenDevice()
- .getDefaultConfiguration();
+ graphicsConfig = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice()
+ .getDefaultConfiguration();
else
- graphicsConfiguration = gc;
- }
-
- GraphicsConfiguration getGraphicsConfigurationImpl()
- {
- if (graphicsConfiguration != null)
- return graphicsConfiguration;
-
- return super.getGraphicsConfigurationImpl();
+ graphicsConfig = gc;
}
/**
@@ -1073,9 +1064,14 @@ public class Window extends Container implements Accessible
*/
public GraphicsConfiguration getGraphicsConfiguration()
{
- if (graphicsConfiguration != null) return graphicsConfiguration;
- if (peer != null) return peer.getGraphicsConfiguration();
- return null;
+ GraphicsConfiguration conf = graphicsConfig;
+ if (conf == null)
+ {
+ conf = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice().getDefaultConfiguration();
+ graphicsConfig = conf;
+ }
+ return conf;
}
protected void processWindowFocusEvent(WindowEvent event)
diff --git a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java
index e163fe067e2..7f296b5941a 100644
--- a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java
+++ b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java
@@ -38,12 +38,21 @@ exception statement from your version. */
package java.awt.datatransfer;
-import gnu.classpath.NotImplementedException;
-
+import java.awt.Toolkit;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
import java.util.WeakHashMap;
/**
@@ -72,19 +81,102 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
* This map maps native <code>String</code>s to lists of
* <code>DataFlavor</code>s
*/
- private HashMap nativeToFlavorMap = new HashMap();
+ private HashMap<String,List<DataFlavor>> nativeToFlavorMap =
+ new HashMap<String,List<DataFlavor>>();
/**
* This map maps <code>DataFlavor</code>s to lists of native
* <code>String</code>s
*/
- private HashMap flavorToNativeMap = new HashMap();
+ private HashMap<DataFlavor, List<String>> flavorToNativeMap =
+ new HashMap<DataFlavor, List<String>>();
/**
* Private constructor.
*/
private SystemFlavorMap ()
{
+ AccessController.doPrivileged
+ (new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ try
+ {
+ // Load installed flavormap.properties first.
+ String sep = File.separator;
+ File propsFile =
+ new File(System.getProperty("gnu.classpath.home.url")
+ + sep + "accessibility.properties");
+ InputStream in = new FileInputStream(propsFile);
+ Properties props = new Properties();
+ props.load(in);
+ in.close();
+
+ String augmented = Toolkit.getProperty("AWT.DnD.flavorMapFileURL",
+ null);
+ if (augmented != null)
+ {
+ URL url = new URL(augmented);
+ in = url.openStream();
+ props.load(in);
+ }
+ setupMapping(props);
+ }
+ catch (IOException ex)
+ {
+ // Can't do anything about it.
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Sets up the mapping from native to mime types and vice versa as specified
+ * in the flavormap.properties file.
+ *
+ * This is package private to avoid an accessor method.
+ *
+ * @param props the properties file
+ */
+ void setupMapping(Properties props)
+ {
+ Enumeration propNames = props.propertyNames();
+ while (propNames.hasMoreElements())
+ {
+ try
+ {
+ String nat = (String) propNames.nextElement();
+ String mime = (String) props.getProperty(nat);
+ // Check valid mime type.
+ MimeType type = new MimeType(mime);
+ DataFlavor flav = new DataFlavor(mime);
+
+ List<DataFlavor> flavs = nativeToFlavorMap.get(nat);
+ if (flavs == null)
+ {
+ flavs = new ArrayList<DataFlavor>();
+ nativeToFlavorMap.put(nat, flavs);
+ }
+ List<String> nats = flavorToNativeMap.get(flav);
+ if (nats == null)
+ {
+ nats = new ArrayList<String>();
+ flavorToNativeMap.put(flav, nats);
+ }
+ flavs.add(flav);
+ nats.add(nat);
+ }
+ catch (ClassNotFoundException ex)
+ {
+ // Skip.
+ }
+ catch (MimeTypeParseException ex)
+ {
+ // Skip.
+ }
+ }
}
/**
@@ -263,16 +355,52 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
* specified native and a DataFlavor whose MIME type is a decoded
* version of the native.
*/
- public List<DataFlavor> getFlavorsForNative (String nat)
- throws NotImplementedException
+ public List<DataFlavor> getFlavorsForNative(String nat)
{
- throw new Error ("Not implemented");
+ List<DataFlavor> ret = new ArrayList<DataFlavor>();
+ if (nat == null)
+ {
+ Collection<List<DataFlavor>> all = nativeToFlavorMap.values();
+ for (List<DataFlavor> list : all)
+ {
+ for (DataFlavor flav : list)
+ {
+ if (! ret.contains(flav))
+ ret.add(flav);
+ }
+ }
+ }
+ else
+ {
+ List<DataFlavor> list = nativeToFlavorMap.get(nat);
+ if (list != null)
+ ret.addAll(list);
+ }
+ return ret;
}
public List<String> getNativesForFlavor (DataFlavor flav)
- throws NotImplementedException
{
- throw new Error ("Not implemented");
+ List<String> ret = new ArrayList<String>();
+ if (flav == null)
+ {
+ Collection<List<String>> all = flavorToNativeMap.values();
+ for (List<String> list : all)
+ {
+ for (String nat : list)
+ {
+ if (! ret.contains(nat))
+ ret.add(nat);
+ }
+ }
+ }
+ else
+ {
+ List<String> list = flavorToNativeMap.get(flav);
+ if (list != null)
+ ret.addAll(list);
+ }
+ return ret;
}
/**
@@ -298,10 +426,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
{
if ((nativeStr == null) || (flavor == null))
throw new NullPointerException();
- List flavors = (List) nativeToFlavorMap.get(nativeStr);
+ List<DataFlavor> flavors = nativeToFlavorMap.get(nativeStr);
if (flavors == null)
{
- flavors = new ArrayList();
+ flavors = new ArrayList<DataFlavor>();
nativeToFlavorMap.put(nativeStr, flavors);
}
else
@@ -336,10 +464,10 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
{
if ((nativeStr == null) || (flavor == null))
throw new NullPointerException();
- List natives = (List) flavorToNativeMap.get(flavor);
+ List<String> natives = flavorToNativeMap.get(flavor);
if (natives == null)
{
- natives = new ArrayList();
+ natives = new ArrayList<String>();
flavorToNativeMap.put(flavor, natives);
}
else
diff --git a/libjava/classpath/java/awt/geom/GeneralPath.java b/libjava/classpath/java/awt/geom/GeneralPath.java
index 1e9ede5ee67..fa27d1908c7 100644
--- a/libjava/classpath/java/awt/geom/GeneralPath.java
+++ b/libjava/classpath/java/awt/geom/GeneralPath.java
@@ -79,22 +79,17 @@ import java.awt.Shape;
*/
public final class GeneralPath implements Shape, Cloneable
{
- // WORKAROUND for gcj 4.0.x (x < 3)
- // fully qualify PathIterator constants.
-
/** Same constant as {@link PathIterator#WIND_EVEN_ODD}. */
- public static final int WIND_EVEN_ODD
- = java.awt.geom.PathIterator.WIND_EVEN_ODD;
+ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
/** Same constant as {@link PathIterator#WIND_NON_ZERO}. */
- public static final int WIND_NON_ZERO
- = java.awt.geom.PathIterator.WIND_NON_ZERO;
+ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
/** Initial size if not specified. */
private static final int INIT_SIZE = 10;
/** A big number, but not so big it can't survive a few float operations */
- private static final double BIG_VALUE = java.lang.Double.MAX_VALUE / 10.0;
+ private static final double BIG_VALUE = Double.MAX_VALUE / 10.0;
/** The winding rule.
* This is package-private to avoid an accessor method.
diff --git a/libjava/classpath/java/awt/image/BufferedImage.java b/libjava/classpath/java/awt/image/BufferedImage.java
index ef3141d0ead..c9879461ce2 100644
--- a/libjava/classpath/java/awt/image/BufferedImage.java
+++ b/libjava/classpath/java/awt/image/BufferedImage.java
@@ -39,7 +39,9 @@ exception statement from your version. */
package java.awt.image;
import gnu.java.awt.Buffers;
+import gnu.java.awt.ClasspathGraphicsEnvironment;
import gnu.java.awt.ComponentDataBlitOp;
+import gnu.java.awt.peer.gtk.CairoSurface;
import java.awt.Graphics;
import java.awt.Graphics2D;
@@ -83,7 +85,7 @@ public class BufferedImage extends Image
/**
* Vector of TileObservers (or null)
*/
- Vector tileObservers;
+ Vector<TileObserver> tileObservers;
/**
* The image's WritableRaster
@@ -143,39 +145,39 @@ public class BufferedImage extends Image
{
SampleModel sm = null;
ColorModel cm = null;
- boolean premultiplied = (type == BufferedImage.TYPE_INT_ARGB_PRE ||
- type == BufferedImage.TYPE_4BYTE_ABGR_PRE);
+ boolean premultiplied = (type == BufferedImage.TYPE_INT_ARGB_PRE
+ || type == BufferedImage.TYPE_4BYTE_ABGR_PRE);
switch( type )
{
case BufferedImage.TYPE_INT_RGB:
- sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
- width, height,
- new int[]{ 0x00FF0000,
- 0x0000FF00,
- 0x000000FF } ) ;
- cm = new DirectColorModel( 24, 0xff0000, 0xff00, 0xff );
- break;
+ sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
+ width, height,
+ new int[]{ 0x00FF0000,
+ 0x0000FF00,
+ 0x000000FF } ) ;
+ cm = new DirectColorModel( 24, 0xff0000, 0xff00, 0xff );
+ break;
case BufferedImage.TYPE_3BYTE_BGR:
- sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
- width, height,
- 3, width * 3,
- new int[]{ 2, 1, 0 } );
- cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
- false, false,
- BufferedImage.OPAQUE,
- DataBuffer.TYPE_BYTE);
+ sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
+ width, height,
+ 3, width * 3,
+ new int[]{ 2, 1, 0 } );
+ cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ false, false,
+ BufferedImage.OPAQUE,
+ DataBuffer.TYPE_BYTE);
break;
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
- sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
- width, height,
- new int[]{ 0x00FF0000,
- 0x0000FF00,
- 0x000000FF,
- 0xFF000000 } );
+ sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
+ width, height,
+ new int[]{ 0x00FF0000,
+ 0x0000FF00,
+ 0x000000FF,
+ 0xFF000000 } );
if (premultiplied)
cm = new DirectColorModel( ColorSpace.getInstance(ColorSpace.CS_sRGB),
32, 0xff0000, 0xff00, 0xff, 0xff000000,
@@ -183,7 +185,8 @@ public class BufferedImage extends Image
Buffers.smallestAppropriateTransferType(32));
else
cm = new DirectColorModel( 32, 0xff0000, 0xff00, 0xff, 0xff000000 );
- break;
+
+ break;
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
@@ -195,57 +198,58 @@ public class BufferedImage extends Image
true, premultiplied,
BufferedImage.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
- break;
+ break;
case BufferedImage.TYPE_INT_BGR:
- sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
- width, height,
- new int[]{ 0x000000FF,
- 0x0000FF00,
- 0x00FF0000 } ) ;
- cm = new DirectColorModel( 24, 0xff, 0xff00, 0xff0000 );
+ sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
+ width, height,
+ new int[]{ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000 } ) ;
+ cm = new DirectColorModel( 24, 0xff, 0xff00, 0xff0000 );
break;
case BufferedImage.TYPE_USHORT_565_RGB:
- sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
- width, height,
- new int[]{ 0xF800,
- 0x7E0,
- 0x1F } ) ;
- cm = new DirectColorModel( 16, 0xF800, 0x7E0, 0x1F );
- break;
+ sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
+ width, height,
+ new int[]{ 0xF800,
+ 0x7E0,
+ 0x1F } ) ;
+ cm = new DirectColorModel( 16, 0xF800, 0x7E0, 0x1F );
+ break;
+
case BufferedImage.TYPE_USHORT_555_RGB:
- sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
- width, height,
- new int[]{ 0x7C00,
- 0x3E0,
- 0x1F } ) ;
- cm = new DirectColorModel( 15, 0x7C00, 0x3E0, 0x1F );
- break;
+ sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
+ width, height,
+ new int[]{ 0x7C00,
+ 0x3E0,
+ 0x1F } ) ;
+ cm = new DirectColorModel( 15, 0x7C00, 0x3E0, 0x1F );
+ break;
case BufferedImage.TYPE_BYTE_INDEXED:
- cm = createDefaultIndexedColorModel( false );
+ cm = createDefaultIndexedColorModel( false );
case BufferedImage.TYPE_BYTE_GRAY:
- sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
- width, height,
- 1, width, new int[]{ 0 } );
- break;
+ sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
+ width, height,
+ 1, width, new int[]{ 0 } );
+ break;
case BufferedImage.TYPE_USHORT_GRAY:
- sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_USHORT,
- width, height,
- 1, width, new int[]{ 0 } );
- break;
+ sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_USHORT,
+ width, height,
+ 1, width, new int[]{ 0 } );
+ break;
case BufferedImage.TYPE_BYTE_BINARY:
- cm = createDefaultIndexedColorModel( true );
- sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
- width, height, 1);
- break;
+ cm = createDefaultIndexedColorModel( true );
+ sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
+ width, height, 1);
+ break;
default:
- sm = null;
+ sm = null;
}
if( sm == null )
@@ -253,33 +257,41 @@ public class BufferedImage extends Image
if( cm == null ) // only for the grayscale types
{
- int buftype;
- int[] bits = new int[1];
- if( type == BufferedImage.TYPE_BYTE_GRAY )
- {
- buftype = DataBuffer.TYPE_BYTE;
- bits[0] = 8;
- }
- else
- {
- buftype = DataBuffer.TYPE_USHORT;
- bits[0] = 16;
- }
- ColorSpace graySpace = ColorSpace.getInstance( ColorSpace.CS_GRAY );
-
- cm = new ComponentColorModel( graySpace, bits, false, false,
- Transparency.OPAQUE, buftype );
+ int buftype;
+ int[] bits = new int[1];
+ if( type == BufferedImage.TYPE_BYTE_GRAY )
+ {
+ buftype = DataBuffer.TYPE_BYTE;
+ bits[0] = 8;
+ }
+ else
+ {
+ buftype = DataBuffer.TYPE_USHORT;
+ bits[0] = 16;
+ }
+ ColorSpace graySpace = ColorSpace.getInstance( ColorSpace.CS_GRAY );
+
+ cm = new ComponentColorModel( graySpace, bits, false, false,
+ Transparency.OPAQUE, buftype );
}
- init( cm,
- Raster.createWritableRaster(sm, new Point( 0, 0 ) ),
- premultiplied,
- null, // no properties
- type );
+ WritableRaster rst = null;
+
+ // Attempt to create an accelerated backend for this image
+ GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ if (env instanceof ClasspathGraphicsEnvironment)
+ rst = ((ClasspathGraphicsEnvironment)env).createRaster(cm, sm);
+
+ // Default to a standard Java raster & databuffer if needed
+ if (rst == null)
+ rst = Raster.createWritableRaster(sm, new Point( 0, 0 ) );
+
+ init(cm, rst, premultiplied,
+ null, // no properties
+ type );
}
- public BufferedImage(int w, int h, int type,
- IndexColorModel indexcolormodel)
+ public BufferedImage(int w, int h, int type, IndexColorModel indexcolormodel)
{
if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED))
throw new IllegalArgumentException("Type must be TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED");
@@ -289,27 +301,21 @@ public class BufferedImage extends Image
throw new IllegalArgumentException("Byte type cannot have a larger than 256-color palette.");
init( indexcolormodel,
- indexcolormodel.createCompatibleWritableRaster(w, h),
- indexcolormodel.isAlphaPremultiplied(),
- null, // no properties
- type );
+ indexcolormodel.createCompatibleWritableRaster(w, h),
+ indexcolormodel.isAlphaPremultiplied(),
+ null, // no properties
+ type );
}
- public BufferedImage(ColorModel colormodel,
- WritableRaster writableraster,
- boolean premultiplied,
- Hashtable<?,?> properties)
+ public BufferedImage(ColorModel colormodel, WritableRaster writableraster,
+ boolean premultiplied, Hashtable<?,?> properties)
{
- init(colormodel, writableraster, premultiplied, properties,
- TYPE_CUSTOM);
+ init(colormodel, writableraster, premultiplied, properties, TYPE_CUSTOM);
}
- private void init(ColorModel cm,
- WritableRaster writableraster,
- boolean premultiplied,
- Hashtable properties,
- int type)
+ private void init(ColorModel cm, WritableRaster writableraster,
+ boolean premultiplied, Hashtable properties, int type)
{
raster = writableraster;
colorModel = cm;
@@ -329,29 +335,32 @@ public class BufferedImage extends Image
{
if( binary )
{
- byte[] t = new byte[]{ 0, (byte)255 };
- return new IndexColorModel( 1, 2, t, t, t );
+ byte[] t = new byte[]{ 0, (byte)255 };
+ return new IndexColorModel( 1, 2, t, t, t );
}
byte[] r = new byte[256];
byte[] g = new byte[256];
byte[] b = new byte[256];
+
int index = 0;
for( int i = 0; i < 6; i++ )
for( int j = 0; j < 6; j++ )
- for( int k = 0; k < 6; k++ )
- {
- r[ index ] = (byte)(i * 51);
- g[ index ] = (byte)(j * 51);
- b[ index ] = (byte)(k * 51);
- index++;
- }
+ for( int k = 0; k < 6; k++ )
+ {
+ r[ index ] = (byte)(i * 51);
+ g[ index ] = (byte)(j * 51);
+ b[ index ] = (byte)(k * 51);
+ index++;
+ }
+
while( index < 256 )
{
- r[ index ] = g[ index ] = b[ index ] =
- (byte)(18 + (index - 216) * 6);
- index++;
+ r[ index ] = g[ index ] = b[ index ] =
+ (byte)(18 + (index - 216) * 6);
+ index++;
}
+
return new IndexColorModel( 8, 256, r, g, b );
}
@@ -375,12 +384,13 @@ public class BufferedImage extends Image
// create a src child that has the right bounds...
WritableRaster src =
raster.createWritableChild(x, y, w, h, x, y,
- null // same bands
- );
+ null); // same bands
+
if (src.getSampleModel () instanceof ComponentSampleModel
&& dest.getSampleModel () instanceof ComponentSampleModel)
// Refer to ComponentDataBlitOp for optimized data blitting:
ComponentDataBlitOp.INSTANCE.filter(src, dest);
+
else
{
// slower path
@@ -397,7 +407,8 @@ public class BufferedImage extends Image
return env.createGraphics (this);
}
- public void flush() {
+ public void flush()
+ {
}
public WritableRaster getAlphaRaster()
@@ -512,26 +523,24 @@ public class BufferedImage extends Image
public int getRGB(int x, int y)
{
- Object rgbElem = raster.getDataElements(x, y,
- null // create as needed
- );
+ Object rgbElem = raster.getDataElements(x, y, null);
return colorModel.getRGB(rgbElem);
}
- public int[] getRGB(int startX, int startY, int w, int h,
- int[] rgbArray,
- int offset, int scanlineStride)
+ public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray,
+ int offset, int scanlineStride)
{
if (rgbArray == null)
- {
- /*
- 000000000000000000
- 00000[#######----- [ = start
- -----########----- ] = end
- -----#######]00000
- 000000000000000000 */
- int size = (h-1)*scanlineStride + w;
- rgbArray = new int[size];
+ {
+ /*
+ 000000000000000000
+ 00000[#######----- [ = start
+ -----########----- ] = end
+ -----#######]00000
+ 000000000000000000
+ */
+ int size = (h-1)*scanlineStride + w;
+ rgbArray = new int[size];
}
int endX = startX + w;
@@ -547,15 +556,15 @@ public class BufferedImage extends Image
Object rgbElem = null;
for (int y=startY; y<endY; y++)
{
- int xoffset = offset;
- for (int x=startX; x<endX; x++)
- {
- int rgb;
- rgbElem = raster.getDataElements(x, y, rgbElem);
- rgb = colorModel.getRGB(rgbElem);
- rgbArray[xoffset++] = rgb;
- }
- offset += scanlineStride;
+ int xoffset = offset;
+ for (int x=startX; x<endX; x++)
+ {
+ int rgb;
+ rgbElem = raster.getDataElements(x, y, rgbElem);
+ rgb = colorModel.getRGB(rgbElem);
+ rgbArray[xoffset++] = rgb;
+ }
+ offset += scanlineStride;
}
return rgbArray;
}
@@ -572,14 +581,14 @@ public class BufferedImage extends Image
public ImageProducer getSource()
{
- return new ImageProducer() {
-
- Vector consumers = new Vector();
+ return new ImageProducer()
+ {
+ Vector<ImageConsumer> consumers = new Vector<ImageConsumer>();
public void addConsumer(ImageConsumer ic)
{
- if(!consumers.contains(ic))
- consumers.add(ic);
+ if(!consumers.contains(ic))
+ consumers.add(ic);
}
public boolean isConsumer(ImageConsumer ic)
@@ -589,7 +598,7 @@ public class BufferedImage extends Image
public void removeConsumer(ImageConsumer ic)
{
- consumers.remove(ic);
+ consumers.remove(ic);
}
public void startProduction(ImageConsumer ic)
@@ -610,9 +619,9 @@ public class BufferedImage extends Image
consumers.add(ic);
- for(int i=0;i<consumers.size();i++)
+ for(int i = 0; i < consumers.size(); i++)
{
- ImageConsumer c = (ImageConsumer) consumers.elementAt(i);
+ ImageConsumer c = consumers.elementAt(i);
c.setHints(ImageConsumer.SINGLEPASS);
c.setDimensions(getWidth(), getHeight());
c.setPixels(x, y, width, height, model, pixels, offset, stride);
@@ -638,10 +647,8 @@ public class BufferedImage extends Image
WritableRaster subRaster =
getRaster().createWritableChild(x, y, w, h, 0, 0, null);
- return new BufferedImage(getColorModel(),
- subRaster,
- isPremultiplied,
- properties);
+ return new BufferedImage(getColorModel(), subRaster, isPremultiplied,
+ properties);
}
public Raster getTile(int tileX, int tileY)
@@ -730,9 +737,7 @@ public class BufferedImage extends Image
// create a dest child that has the right bounds...
WritableRaster dest =
- raster.createWritableChild(x, y, w, h, x, y,
- null // same bands
- );
+ raster.createWritableChild(x, y, w, h, x, y, null);
if (src.getSampleModel () instanceof ComponentSampleModel
&& dest.getSampleModel () instanceof ComponentSampleModel)
@@ -762,14 +767,14 @@ public class BufferedImage extends Image
Object rgbElem = null;
for (int y=startY; y<endY; y++)
{
- int xoffset = offset;
- for (int x=startX; x<endX; x++)
- {
- int argb = argbArray[xoffset++];
- rgbElem = colorModel.getDataElements(argb, rgbElem);
- raster.setDataElements(x, y, rgbElem);
- }
- offset += scanlineStride;
+ int xoffset = offset;
+ for (int x=startX; x<endX; x++)
+ {
+ int argb = argbArray[xoffset++];
+ rgbElem = colorModel.getDataElements(argb, rgbElem);
+ raster.setDataElements(x, y, rgbElem);
+ }
+ offset += scanlineStride;
}
}
@@ -800,7 +805,7 @@ public class BufferedImage extends Image
public void addTileObserver (TileObserver to)
{
if (tileObservers == null)
- tileObservers = new Vector ();
+ tileObservers = new Vector<TileObserver>();
tileObservers.add (to);
}
diff --git a/libjava/classpath/java/awt/image/ComponentSampleModel.java b/libjava/classpath/java/awt/image/ComponentSampleModel.java
index bccabbbcadb..73e7fb4d3d0 100644
--- a/libjava/classpath/java/awt/image/ComponentSampleModel.java
+++ b/libjava/classpath/java/awt/image/ComponentSampleModel.java
@@ -36,12 +36,8 @@ exception statement from your version. */
package java.awt.image;
-import gnu.java.awt.Buffers;
-
import java.util.Arrays;
-/* FIXME: This class does not yet support data type TYPE_SHORT */
-
/**
* ComponentSampleModel supports a flexible organization of pixel samples in
* memory, permitting pixel samples to be interleaved by band, by scanline,
@@ -88,9 +84,7 @@ public class ComponentSampleModel extends SampleModel
* corresponding sample for the next pixel in the same row.
*/
protected int pixelStride;
-
- private boolean tightPixelPacking = false;
-
+
/**
* Creates a new sample model that assumes that all bands are stored in a
* single bank of the {@link DataBuffer}.
@@ -203,22 +197,6 @@ public class ComponentSampleModel extends SampleModel
this.scanlineStride = scanlineStride;
this.pixelStride = pixelStride;
- // See if we can use some speedups
-
- /* FIXME: May these checks should be reserved for the
- PixelInterleavedSampleModel? */
-
- if (pixelStride == numBands)
- {
- tightPixelPacking = true;
- for (int b = 0; b < numBands; b++) {
- if ((bandOffsets[b] != b) || (bankIndices[b] != 0))
- {
- tightPixelPacking = false;
- break;
- }
- }
- }
}
/**
@@ -275,8 +253,30 @@ public class ComponentSampleModel extends SampleModel
highestOffset = Math.max(highestOffset, bandOffsets[b]);
int size = pixelStride * (width - 1) + scanlineStride * (height - 1)
+ highestOffset + 1;
-
- return Buffers.createBuffer(getDataType(), size, numBanks);
+
+ DataBuffer buffer = null;
+ switch (getTransferType())
+ {
+ case DataBuffer.TYPE_BYTE:
+ buffer = new DataBufferByte(size, numBanks);
+ break;
+ case DataBuffer.TYPE_SHORT:
+ buffer = new DataBufferShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ buffer = new DataBufferUShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ buffer = new DataBufferInt(size, numBanks);
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ buffer = new DataBufferFloat(size, numBanks);
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ buffer = new DataBufferDouble(size, numBanks);
+ break;
+ }
+ return buffer;
}
/**
@@ -424,239 +424,80 @@ public class ComponentSampleModel extends SampleModel
*/
public Object getDataElements(int x, int y, Object obj, DataBuffer data)
{
- int xyOffset = pixelStride * x + scanlineStride * y;
-
- int[] totalBandDataOffsets = new int[numBands];
-
- /* Notice that band and bank offsets are different. Band offsets
- are managed by the sample model, and bank offsets are managed
- by the data buffer. Both must be accounted for. */
-
- /* FIXME: For single pixels, it is probably easier to simple
- call getElem instead of calculating the bank offset ourself.
-
- On the other hand, then we need to push the value through
- the int type returned by the getElem method. */
-
- int[] bankOffsets = data.getOffsets();
-
- for (int b = 0; b < numBands; b++)
+ int type = getTransferType();
+ int numDataEls = getNumDataElements();
+ int offset = y * scanlineStride + x * pixelStride;
+ switch (type)
{
- totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]]
- + xyOffset;
- }
-
- try
- {
- switch (getTransferType())
+ case DataBuffer.TYPE_BYTE:
+ byte[] bData;
+ if (obj == null)
+ bData = new byte[numDataEls];
+ else
+ bData = (byte[]) obj;
+ for (int i = 0; i < numDataEls; i++)
{
- case DataBuffer.TYPE_BYTE:
- DataBufferByte inByte = (DataBufferByte) data;
- byte[] outByte = (byte[]) obj;
- if (outByte == null)
- outByte = new byte[numBands];
-
- for (int b = 0; b < numBands; b++)
- {
- int dOffset = totalBandDataOffsets[b];
- outByte[b] = inByte.getData(bankIndices[b])[dOffset];
- }
- return outByte;
-
- case DataBuffer.TYPE_USHORT:
- DataBufferUShort inUShort = (DataBufferUShort) data;
- short[] outUShort = (short[]) obj;
- if (outUShort == null)
- outUShort = new short[numBands];
-
- for (int b = 0; b < numBands; b++)
- {
- int dOffset = totalBandDataOffsets[b];
- outUShort[b] = inUShort.getData(bankIndices[b])[dOffset];
- }
- return outUShort;
-
- case DataBuffer.TYPE_SHORT:
- DataBufferShort inShort = (DataBufferShort) data;
- short[] outShort = (short[]) obj;
- if (outShort == null)
- outShort = new short[numBands];
-
- for (int b = 0; b < numBands; b++)
- {
- int dOffset = totalBandDataOffsets[b];
- outShort[b] = inShort.getData(bankIndices[b])[dOffset];
- }
- return outShort;
-
- case DataBuffer.TYPE_INT:
- DataBufferInt inInt = (DataBufferInt) data;
- int[] outInt = (int[]) obj;
- if (outInt == null)
- outInt = new int[numBands];
-
- for (int b = 0; b < numBands; b++)
- {
- int dOffset = totalBandDataOffsets[b];
- outInt[b] = inInt.getData(bankIndices[b])[dOffset];
- }
- return outInt;
-
- case DataBuffer.TYPE_FLOAT:
- DataBufferFloat inFloat = (DataBufferFloat) data;
- float[] outFloat = (float[]) obj;
- if (outFloat == null)
- outFloat = new float[numBands];
-
- for (int b = 0; b < numBands; b++)
- {
- int dOffset = totalBandDataOffsets[b];
- outFloat[b] = inFloat.getData(bankIndices[b])[dOffset];
- }
- return outFloat;
-
- case DataBuffer.TYPE_DOUBLE:
- DataBufferDouble inDouble = (DataBufferDouble) data;
- double[] outDouble = (double[]) obj;
- if (outDouble == null)
- outDouble = new double[numBands];
-
- for (int b = 0; b < numBands; b++)
- {
- int dOffset = totalBandDataOffsets[b];
- outDouble[b] = inDouble.getData(bankIndices[b])[dOffset];
- }
- return outDouble;
-
- default:
- throw new IllegalStateException("unknown transfer type "
- + getTransferType());
+ bData[i] = (byte) data.getElem(bankIndices[i],
+ offset + bandOffsets[i]);
}
- }
- catch (ArrayIndexOutOfBoundsException aioobe)
- {
- String msg = "While reading data elements, " +
- "x=" + x + ", y=" + y +", " + ", xyOffset=" + xyOffset +
- ", data.getSize()=" + data.getSize() + ": " + aioobe;
- throw new ArrayIndexOutOfBoundsException(msg);
- }
- }
-
- /**
- * Returns the samples for the pixels in the region defined by
- * <code>(x, y, w, h)</code> in a primitive array (the array type is
- * determined by the data type for this model). The <code>obj</code>
- * argument provides an option to supply an existing array to hold the
- * result, if this is <code>null</code> a new array will be allocated.
- *
- * @param x the x-coordinate.
- * @param y the y-coordinate.
- * @param w the width.
- * @param h the height.
- * @param obj a primitive array that, if not <code>null</code>, will be
- * used to store and return the sample values.
- * @param data the data buffer (<code>null</code> not permitted).
- *
- * @return An array of sample values for the specified pixels.
- *
- * @see #setDataElements(int, int, int, int, Object, DataBuffer)
- */
- public Object getDataElements(int x, int y, int w, int h, Object obj,
- DataBuffer data)
- {
- if (!tightPixelPacking)
- {
- return super.getDataElements(x, y, w, h, obj, data);
- }
-
- // using get speedup
-
- // We can copy whole rows
- int rowSize = w * numBands;
- int dataSize = rowSize * h;
-
- DataBuffer transferBuffer = Buffers.createBuffer(getTransferType(), obj,
- dataSize);
- obj = Buffers.getData(transferBuffer);
-
- int inOffset = pixelStride * x + scanlineStride * y + data.getOffset();
- // Assumes only one band is used
-
- /* We don't add band offsets since we assume that bands have
- offsets 0, 1, 2, ... */
-
- // See if we can copy everything in one go
- if (scanlineStride == rowSize)
- {
- // Collapse scan lines:
- rowSize *= h;
- // We ignore scanlineStride since it won't be of any use
- h = 1;
- }
-
- int outOffset = 0;
- Object inArray = Buffers.getData(data);
- for (int yd = 0; yd < h; yd++)
- {
- System.arraycopy(inArray, inOffset, obj, outOffset, rowSize);
- inOffset += scanlineStride;
- outOffset += rowSize;
+ obj = bData;
+ break;
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ short[] sData;
+ if (obj == null)
+ sData = new short[numDataEls];
+ else
+ sData = (short[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ sData[i] = (short) data.getElem(bankIndices[i],
+ offset + bandOffsets[i]);
+ }
+ obj = sData;
+ break;
+ case DataBuffer.TYPE_INT:
+ int[] iData;
+ if (obj == null)
+ iData = new int[numDataEls];
+ else
+ iData = (int[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ iData[i] = data.getElem(bankIndices[i], offset + bandOffsets[i]);
+ }
+ obj = iData;
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ float[] fData;
+ if (obj == null)
+ fData = new float[numDataEls];
+ else
+ fData = (float[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ fData[i] = data.getElemFloat(bankIndices[i],
+ offset + bandOffsets[i]);
+ }
+ obj = fData;
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ double[] dData;
+ if (obj == null)
+ dData = new double[numDataEls];
+ else
+ dData = (double[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ dData[i] = data.getElemDouble(bankIndices[i],
+ offset + bandOffsets[i]);
+ }
+ obj = dData;
+ break;
}
return obj;
}
- /**
- * Sets the samples for the pixels in the region defined by
- * <code>(x, y, w, h)</code> from a supplied primitive array (the array type
- * must be consistent with the data type for this model).
- *
- * @param x the x-coordinate.
- * @param y the y-coordinate.
- * @param w the width.
- * @param h the height.
- * @param obj a primitive array containing the sample values.
- * @param data the data buffer (<code>null</code> not permitted).
- *
- * @see #getDataElements(int, int, int, int, Object, DataBuffer)
- */
- public void setDataElements(int x, int y, int w, int h,
- Object obj, DataBuffer data)
- {
- if (!tightPixelPacking)
- {
- super.setDataElements(x, y, w, h, obj, data);
- return;
- }
-
- // using set speedup, we can copy whole rows
- int rowSize = w * numBands;
- int dataSize = rowSize * h;
-
- DataBuffer transferBuffer
- = Buffers.createBufferFromData(getTransferType(), obj, dataSize);
-
- int[] bankOffsets = data.getOffsets();
-
- int outOffset = pixelStride * x + scanlineStride * y + bankOffsets[0];
- // same assumptions as in get...
-
- // See if we can copy everything in one go
- if (scanlineStride == rowSize)
- {
- // Collapse scan lines:
- rowSize *= h;
- h = 1;
- }
-
- int inOffset = 0;
- Object outArray = Buffers.getData(data);
- for (int yd = 0; yd < h; yd++)
- {
- System.arraycopy(obj, inOffset, outArray, outOffset, rowSize);
- outOffset += scanlineStride;
- inOffset += rowSize;
- }
- }
/**
* Returns all the samples for the pixel at location <code>(x, y)</code>
@@ -764,78 +605,51 @@ public class ComponentSampleModel extends SampleModel
*/
public void setDataElements(int x, int y, Object obj, DataBuffer data)
{
- int offset = pixelStride * x + scanlineStride * y;
- int[] totalBandDataOffsets = new int[numBands];
- int[] bankOffsets = data.getOffsets();
- for (int b = 0; b < numBands; b++)
- totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]]
- + offset;
-
- switch (getTransferType())
+ int type = getTransferType();
+ int numDataEls = getNumDataElements();
+ int offset = y * scanlineStride + x * pixelStride;
+ switch (type)
{
case DataBuffer.TYPE_BYTE:
- {
- DataBufferByte out = (DataBufferByte) data;
- byte[] in = (byte[]) obj;
-
- for (int b = 0; b < numBands; b++)
- out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
-
- return;
- }
- case DataBuffer.TYPE_USHORT:
- {
- DataBufferUShort out = (DataBufferUShort) data;
- short[] in = (short[]) obj;
-
- for (int b = 0; b < numBands; b++)
- out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
-
- return;
- }
+ byte[] bData = (byte[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ data.setElem(bankIndices[i], offset + bandOffsets[i],
+ ((int) bData[i]) & 0xFF);
+ }
+ break;
case DataBuffer.TYPE_SHORT:
- {
- DataBufferShort out = (DataBufferShort) data;
- short[] in = (short[]) obj;
-
- for (int b = 0; b < numBands; b++)
- out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
-
- return;
- }
+ case DataBuffer.TYPE_USHORT:
+ short[] sData = (short[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ data.setElem(bankIndices[i], offset + bandOffsets[i],
+ ((int) sData[i]) & 0xFFFF);
+ }
+ break;
case DataBuffer.TYPE_INT:
- {
- DataBufferInt out = (DataBufferInt) data;
- int[] in = (int[]) obj;
-
- for (int b = 0; b < numBands; b++)
- out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
-
- return;
- }
+ int[] iData = (int[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ data.setElem(bankIndices[i], offset + bandOffsets[i], iData[i]);
+ }
+ break;
case DataBuffer.TYPE_FLOAT:
- {
- DataBufferFloat out = (DataBufferFloat) data;
- float[] in = (float[]) obj;
-
- for (int b = 0; b < numBands; b++)
- out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
-
- return;
- }
+ float[] fData = (float[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ data.setElemFloat(bankIndices[i], offset + bandOffsets[i],
+ fData[i]);
+ }
+ break;
case DataBuffer.TYPE_DOUBLE:
- {
- DataBufferDouble out = (DataBufferDouble) data;
- double[] in = (double[]) obj;
-
- for (int b = 0; b < numBands; b++)
- out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
-
- return;
- }
- default:
- throw new UnsupportedOperationException("transfer type not " +
- "implemented");
+ double[] dData = (double[]) obj;
+ for (int i = 0; i < numDataEls; i++)
+ {
+ data.setElemDouble(bankIndices[i], offset + bandOffsets[i],
+ dData[i]);
+ }
+ break;
}
}
diff --git a/libjava/classpath/java/awt/image/IndexColorModel.java b/libjava/classpath/java/awt/image/IndexColorModel.java
index 46879cc98c9..d8a27d51ff1 100644
--- a/libjava/classpath/java/awt/image/IndexColorModel.java
+++ b/libjava/classpath/java/awt/image/IndexColorModel.java
@@ -134,7 +134,7 @@ public class IndexColorModel extends ColorModel
if (size < 1)
throw new IllegalArgumentException("size < 1");
map_size = size;
- rgb = new int[size];
+ rgb = createColorMap(bits, size);
for (int i = 0; i < size; i++)
{
rgb[i] = (0xff000000
@@ -187,7 +187,7 @@ public class IndexColorModel extends ColorModel
map_size = size;
opaque = (alphas == null);
- rgb = new int[size];
+ rgb = createColorMap(bits, size);
if (alphas == null)
{
for (int i = 0; i < size; i++)
@@ -275,7 +275,7 @@ public class IndexColorModel extends ColorModel
map_size = size;
opaque = !hasAlpha;
- rgb = new int[size];
+ rgb = createColorMap(bits, size);
if (hasAlpha)
{
int alpha;
@@ -360,7 +360,7 @@ public class IndexColorModel extends ColorModel
throw new IllegalArgumentException("size < 1");
map_size = size;
opaque = !hasAlpha;
- rgb = new int[size];
+ rgb = createColorMap(bits, size);
if (!hasAlpha)
for (int i = 0; i < size; i++)
rgb[i] = cmap[i + start] | 0xff000000;
@@ -419,7 +419,7 @@ public class IndexColorModel extends ColorModel
this.trans = -1;
this.validBits = validBits;
- rgb = new int[size];
+ rgb = createColorMap(bits, size);
if (!hasAlpha)
for (int i = 0; i < size; i++)
rgb[i] = cmap[i + start] | 0xff000000;
@@ -726,4 +726,11 @@ public class IndexColorModel extends ColorModel
}
}
}
+
+ private int[] createColorMap(int bits, int size)
+ {
+ // According to a Mauve test, the RI allocates at least 256 entries here.
+ int realSize = Math.max(256, Math.max(1 << bits, size));
+ return new int[realSize];
+ }
}
diff --git a/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java
index 9ed948c54f3..1b0ac3f7904 100644
--- a/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java
+++ b/libjava/classpath/java/awt/image/SinglePixelPackedSampleModel.java
@@ -39,7 +39,6 @@ package java.awt.image;
import java.util.Arrays;
import gnu.java.awt.BitMaskExtent;
-import gnu.java.awt.Buffers;
/**
* A <code>SampleModel</code> used when all samples are stored in a single
@@ -151,14 +150,25 @@ public class SinglePixelPackedSampleModel extends SampleModel
*/
public DataBuffer createDataBuffer()
{
- int size;
-
// We can save (scanlineStride - width) pixels at the very end of
// the buffer. The Sun reference implementation (J2SE 1.3.1 and
// 1.4.1_01) seems to do this; tested with Mauve test code.
- size = scanlineStride * (height - 1) + width;
+ int size = scanlineStride * (height - 1) + width;
- return Buffers.createBuffer(getDataType(), size);
+ DataBuffer buffer = null;
+ switch (getTransferType())
+ {
+ case DataBuffer.TYPE_BYTE:
+ buffer = new DataBufferByte(size);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ buffer = new DataBufferUShort(size);
+ break;
+ case DataBuffer.TYPE_INT:
+ buffer = new DataBufferInt(size);
+ break;
+ }
+ return buffer;
}
/**
@@ -253,73 +263,39 @@ public class SinglePixelPackedSampleModel extends SampleModel
public Object getDataElements(int x, int y, Object obj,
DataBuffer data)
{
- int offset = scanlineStride*y + x + data.getOffset();
-
- return Buffers.getData(data, offset, obj,
- 0, // destination offset,
- 1 // length
- );
- }
-
- /**
- * This is a more efficient implementation of the default implementation in
- * the super class.
- * @param x The x-coordinate of the pixel rectangle to store in
- * <code>obj</code>.
- * @param y The y-coordinate of the pixel rectangle to store in
- * <code>obj</code>.
- * @param w The width of the pixel rectangle to store in <code>obj</code>.
- * @param h The height of the pixel rectangle to store in <code>obj</code>.
- * @param obj The primitive array to store the pixels into or null to force
- * creation.
- * @param data The DataBuffer that is the source of the pixel data.
- * @return The primitive array containing the pixel data.
- * @see java.awt.image.SampleModel#getDataElements(int, int, int, int,
- * java.lang.Object, java.awt.image.DataBuffer)
- */
- public Object getDataElements(int x, int y, int w, int h, Object obj,
- DataBuffer data)
- {
- int size = w*h;
- int dataSize = size;
- Object pixelData = null;
- switch (getTransferType())
- {
+ int type = getTransferType();
+ Object ret = null;
+ switch (type)
+ {
case DataBuffer.TYPE_BYTE:
- pixelData = ((DataBufferByte) data).getData();
- if (obj == null) obj = new byte[dataSize];
+ {
+ byte[] in = (byte[]) obj;
+ if (in == null)
+ in = new byte[1];
+ in[0] = (byte) data.getElem(x + y * scanlineStride);
+ ret = in;
+ }
break;
- case DataBuffer.TYPE_USHORT:
- pixelData = ((DataBufferUShort) data).getData();
- if (obj == null) obj = new short[dataSize];
- break;
- case DataBuffer.TYPE_INT:
- pixelData = ((DataBufferInt) data).getData();
- if (obj == null) obj = new int[dataSize];
- break;
- default:
- // Seems like the only sensible thing to do.
- throw new ClassCastException();
- }
- if(x == 0 && scanlineStride == w)
- {
- // The full width need to be copied therefore we can copy in one shot.
- System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj,
- 0, size);
- }
- else
- {
- // Since we do not need the full width we need to copy line by line.
- int outOffset = 0;
- int dataOffset = scanlineStride*y + x + data.getOffset();
- for (int yy = y; yy<(y+h); yy++)
+ case DataBuffer.TYPE_USHORT:
+ {
+ short[] in = (short[]) obj;
+ if (in == null)
+ in = new short[1];
+ in[0] = (short) data.getElem(x + y * scanlineStride);
+ ret = in;
+ }
+ break;
+ case DataBuffer.TYPE_INT:
{
- System.arraycopy(pixelData, dataOffset, obj, outOffset, w);
- dataOffset += scanlineStride;
- outOffset += w;
+ int[] in = (int[]) obj;
+ if (in == null)
+ in = new int[1];
+ in[0] = data.getElem(x + y * scanlineStride);
+ ret = in;
}
+ break;
}
- return obj;
+ return ret;
}
/**
@@ -414,30 +390,29 @@ public class SinglePixelPackedSampleModel extends SampleModel
public void setDataElements(int x, int y, Object obj, DataBuffer data)
{
-
int transferType = getTransferType();
- switch (transferType)
- {
- case DataBuffer.TYPE_BYTE:
- {
- byte[] in = (byte[]) obj;
- data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xff);
- break;
- }
- case DataBuffer.TYPE_USHORT:
- {
- short[] in = (short[]) obj;
+ switch (transferType)
+ {
+ case DataBuffer.TYPE_BYTE:
+ {
+ byte[] in = (byte[]) obj;
+ data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xff);
+ }
+ break;
+ case DataBuffer.TYPE_USHORT:
+ {
+ short[] in = (short[]) obj;
data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xffff);
- break;
- }
- case DataBuffer.TYPE_INT:
- {
- int[] in = (int[]) obj;
+ }
+ break;
+ case DataBuffer.TYPE_INT:
+ {
+ int[] in = (int[]) obj;
data.setElem(y * scanlineStride + x, in[0]);
break;
- }
- }
- }
+ }
+ }
+ }
/**
* Sets the samples for the pixel at (x, y) in the specified data buffer to
@@ -479,7 +454,6 @@ public class SinglePixelPackedSampleModel extends SampleModel
DataBuffer data)
{
int inOffset = 0;
- int[] pixel = new int[numBands];
for (int yy=y; yy<(y+h); yy++)
{
int offset = scanlineStride*yy + x;
diff --git a/libjava/classpath/java/awt/peer/DesktopPeer.java b/libjava/classpath/java/awt/peer/DesktopPeer.java
new file mode 100644
index 00000000000..355d293b311
--- /dev/null
+++ b/libjava/classpath/java/awt/peer/DesktopPeer.java
@@ -0,0 +1,64 @@
+/* DesktopPeer.java -- Interface to enable access to common applications
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+package java.awt.peer;
+
+import java.awt.Desktop.Action;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * @author Mario Torre <neugens@limasoftware.net>
+ *
+ */
+public interface DesktopPeer
+{
+ public void browse(URI url) throws IOException;
+
+ public void edit(File file) throws IOException;
+
+ public boolean isSupported(Action action);
+
+ public void mail(URI mailtoURL) throws IOException;
+
+ public void mail() throws IOException;
+
+ public void open(File file) throws IOException;
+
+ public void print(File file) throws IOException;
+}
diff --git a/libjava/classpath/java/awt/print/PrinterJob.java b/libjava/classpath/java/awt/print/PrinterJob.java
index 8afada1675e..3715dd235ec 100644
--- a/libjava/classpath/java/awt/print/PrinterJob.java
+++ b/libjava/classpath/java/awt/print/PrinterJob.java
@@ -264,15 +264,12 @@ public abstract class PrinterJob
* @return Array of stream print services, could be empty.
* @since 1.4
*/
- // FIXME:
- // Enable when StreamPrintServiceFactory has lookupStreamServiceFactories
-// public static StreamPrintServiceFactory[] lookupStreamPrintServices(String mimeType)
-// {
-// return StreamPrintServiceFactory.lookupStreamServiceFactories(
-// new DocFlavor("application/x-java-jvm-local-objectref",
-// "java.awt.print.Pageable"),
-// mimeType);
-// }
+ public static StreamPrintServiceFactory[]
+ lookupStreamPrintServices(String mimeType)
+ {
+ return StreamPrintServiceFactory.lookupStreamPrintServiceFactories(
+ DocFlavor.SERVICE_FORMATTED.PAGEABLE, mimeType);
+ }
/**
* Return the printer for this job. If print services aren't supported by
diff --git a/libjava/classpath/java/beans/ConstructorProperties.java b/libjava/classpath/java/beans/ConstructorProperties.java
new file mode 100644
index 00000000000..4c82c00337f
--- /dev/null
+++ b/libjava/classpath/java/beans/ConstructorProperties.java
@@ -0,0 +1,72 @@
+/* ConstructorProperties.java - Associate constructor params with props
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+
+/**
+ * An annotation used to associate the parameters of a
+ * constructor with the accessor methods that later provide
+ * access to these values. For example, the parameters of
+ * the constructor <code>Person(String name, int age)</code>
+ * may be linked to the bean's two accessors, <code>getName()</code>
+ * and <code>getAge()</code> using
+ * <code>@ConstructorProperties({"name","age"})</code>.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+@Documented @Retention(RUNTIME) @Target(CONSTRUCTOR)
+public @interface ConstructorProperties
+{
+
+ /**
+ * Contains the name of the accessor methods associated
+ * with each constructor parameter.
+ *
+ * @return the accessor method names corresponding to the
+ * constructor parameters.
+ */
+ String[] value();
+
+}
diff --git a/libjava/classpath/java/beans/XMLEncoder.java b/libjava/classpath/java/beans/XMLEncoder.java
index feff68bd360..7242d0c699e 100644
--- a/libjava/classpath/java/beans/XMLEncoder.java
+++ b/libjava/classpath/java/beans/XMLEncoder.java
@@ -248,7 +248,7 @@ public class XMLEncoder extends Encoder
scanEngine.writeObject(o);
- if (get(o) == null);
+ if (get(o) == null)
super.writeObject(o);
accessCounter--;
diff --git a/libjava/classpath/java/io/File.java b/libjava/classpath/java/io/File.java
index 5d1b3ec8516..f34b4dd2b5c 100644
--- a/libjava/classpath/java/io/File.java
+++ b/libjava/classpath/java/io/File.java
@@ -164,6 +164,29 @@ public class File implements Serializable, Comparable<File>
}
/**
+ * This method tests whether or not the current thread is allowed to
+ * to execute the file pointed to by this object. This will be true if and
+ * and only if 1) the file exists and 2) the <code>SecurityManager</code>
+ * (if any) allows access to the file via it's <code>checkExec</code>
+ * method 3) the file is executable.
+ *
+ * @return <code>true</code> if execution is allowed,
+ * <code>false</code> otherwise
+ *
+ * @exception SecurityException If the <code>SecurityManager</code>
+ * does not allow access to the file
+ */
+ public boolean canExecute()
+ {
+ if (!VMFile.exists(path))
+ return false;
+
+ checkExec();
+
+ return VMFile.canExecute(path);
+ }
+
+ /**
* This method creates a new file of zero length with the same name as
* the path of this <code>File</code> object if an only if that file
* does not already exist.
@@ -1123,6 +1146,153 @@ public class File implements Serializable, Comparable<File>
}
/**
+ * This method sets the owner's read permission for the File represented by
+ * this object.
+ *
+ * It is the same as calling <code>setReadable(readable, true)</code>.
+ *
+ * @param <code>readable</code> <code>true</code> to set read permission,
+ * <code>false</code> to unset the read permission.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setReadable(boolean, boolean)
+ * @since 1.6
+ */
+ public boolean setReadable(boolean readable)
+ {
+ return setReadable(readable, true);
+ }
+
+ /**
+ * This method sets the read permissions for the File represented by
+ * this object.
+ *
+ * If <code>ownerOnly</code> is set to <code>true</code> then only the
+ * read permission bit for the owner of the file is changed.
+ *
+ * If <code>ownerOnly</code> is set to <code>false</code>, the file
+ * permissions are changed so that the file can be read by everyone.
+ *
+ * On unix like systems this sets the <code>user</code>, <code>group</code>
+ * and <code>other</code> read bits and is equal to call
+ * <code>chmod a+r</code> on the file.
+ *
+ * @param <code>readable</code> <code>true</code> to set read permission,
+ * <code>false</code> to unset the read permission.
+ * @param <code>ownerOnly</code> <code>true</code> to set read permission
+ * for owner only, <code>false</code> for all.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setReadable(boolean)
+ * @since 1.6
+ */
+ public boolean setReadable(boolean readable, boolean ownerOnly)
+ {
+ checkWrite();
+ return VMFile.setReadable(path, readable, ownerOnly);
+ }
+
+ /**
+ * This method sets the owner's write permission for the File represented by
+ * this object.
+ *
+ * It is the same as calling <code>setWritable(readable, true)</code>.
+ *
+ * @param <code>writable</code> <code>true</code> to set write permission,
+ * <code>false</code> to unset write permission.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setWritable(boolean, boolean)
+ * @since 1.6
+ */
+ public boolean setWritable(boolean writable)
+ {
+ return setWritable(writable, true);
+ }
+
+ /**
+ * This method sets the write permissions for the File represented by
+ * this object.
+ *
+ * If <code>ownerOnly</code> is set to <code>true</code> then only the
+ * write permission bit for the owner of the file is changed.
+ *
+ * If <code>ownerOnly</code> is set to <code>false</code>, the file
+ * permissions are changed so that the file can be written by everyone.
+ *
+ * On unix like systems this set the <code>user</code>, <code>group</code>
+ * and <code>other</code> write bits and is equal to call
+ * <code>chmod a+w</code> on the file.
+ *
+ * @param <code>writable</code> <code>true</code> to set write permission,
+ * <code>false</code> to unset write permission.
+ * @param <code>ownerOnly</code> <code>true</code> to set write permission
+ * for owner only, <code>false</code> for all.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setWritable(boolean)
+ * @since 1.6
+ */
+ public boolean setWritable(boolean writable, boolean ownerOnly)
+ {
+ checkWrite();
+ return VMFile.setWritable(path, writable, ownerOnly);
+ }
+
+ /**
+ * This method sets the owner's execute permission for the File represented
+ * by this object.
+ *
+ * It is the same as calling <code>setExecutable(readable, true)</code>.
+ *
+ * @param <code>executable</code> <code>true</code> to set execute permission,
+ * <code>false</code> to unset execute permission.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setExecutable(boolean, boolean)
+ * @since 1.6
+ */
+ public boolean setExecutable(boolean executable)
+ {
+ return setExecutable(executable, true);
+ }
+
+ /**
+ * This method sets the execute permissions for the File represented by
+ * this object.
+ *
+ * If <code>ownerOnly</code> is set to <code>true</code> then only the
+ * execute permission bit for the owner of the file is changed.
+ *
+ * If <code>ownerOnly</code> is set to <code>false</code>, the file
+ * permissions are changed so that the file can be executed by everyone.
+ *
+ * On unix like systems this set the <code>user</code>, <code>group</code>
+ * and <code>other</code> write bits and is equal to call
+ * <code>chmod a+x</code> on the file.
+ *
+ * @param <code>executable</code> <code>true</code> to set write permission,
+ * <code>false</code> to unset write permission.
+ * @param <code>ownerOnly</code> <code>true</code> to set write permission
+ * for owner only, <code>false</code> for all.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setExecutable(boolean)
+ * @since 1.6
+ */
+ public boolean setExecutable(boolean executable, boolean ownerOnly)
+ {
+ checkWrite();
+ return VMFile.setExecutable(path, executable, ownerOnly);
+ }
+
+ /**
* This method sets the file represented by this object to be read only.
* A read only file or directory cannot be modified. Please note that
* GNU systems allow read only files to be deleted if the directory it
@@ -1315,6 +1485,15 @@ public class File implements Serializable, Comparable<File>
s.checkRead(path);
}
+ private void checkExec()
+ {
+ // Check the SecurityManager
+ SecurityManager s = System.getSecurityManager();
+
+ if (s != null)
+ s.checkExec(path);
+ }
+
/**
* Calling this method requests that the file represented by this object
* be deleted when the virtual machine exits. Note that this request cannot
diff --git a/libjava/classpath/java/io/ObjectInputStream.java b/libjava/classpath/java/io/ObjectInputStream.java
index 735d46cd920..37b2b64489c 100644
--- a/libjava/classpath/java/io/ObjectInputStream.java
+++ b/libjava/classpath/java/io/ObjectInputStream.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package java.io;
+import gnu.classpath.Pair;
import gnu.classpath.VMStackWalker;
import java.lang.reflect.Array;
@@ -50,10 +51,11 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.Map;
import java.util.TreeSet;
-import java.util.Vector;
/**
* @author Tom Tromey (tromey@redhat.com)
@@ -104,7 +106,7 @@ public class ObjectInputStream extends InputStream
this.blockDataInput = new DataInputStream(this);
this.realInputStream = new DataInputStream(in);
this.nextOID = baseWireHandle;
- this.objectLookupTable = new Vector<Object>();
+ handles = new HashMap<Integer,Pair<Boolean,Object>>();
this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
setBlockDataMode(true);
readStreamHeader();
@@ -132,6 +134,70 @@ public class ObjectInputStream extends InputStream
public final Object readObject()
throws ClassNotFoundException, IOException
{
+ return readObject(true);
+ }
+
+ /**
+ * <p>
+ * Returns the next deserialized object read from the
+ * underlying stream in an unshared manner. Any object
+ * returned by this method will not be returned by
+ * subsequent calls to either this method or {@link #readObject()}.
+ * </p>
+ * <p>
+ * This behaviour is achieved by:
+ * </p>
+ * <ul>
+ * <li>Marking the handles created by successful calls to this
+ * method, so that future calls to {@link #readObject()} or
+ * {@link #readUnshared()} will throw an {@link ObjectStreamException}
+ * rather than returning the same object reference.</li>
+ * <li>Throwing an {@link ObjectStreamException} if the next
+ * element in the stream is a reference to an earlier object.</li>
+ * </ul>
+ *
+ * @return a reference to the deserialized object.
+ * @throws ClassNotFoundException if the class of the object being
+ * deserialized can not be found.
+ * @throws StreamCorruptedException if information in the stream
+ * is inconsistent.
+ * @throws ObjectStreamException if the next object has already been
+ * returned by an earlier call to this
+ * method or {@link #readObject()}.
+ * @throws OptionalDataException if primitive data occurs next in the stream.
+ * @throws IOException if an I/O error occurs from the stream.
+ * @since 1.4
+ * @see #readObject()
+ */
+ public Object readUnshared()
+ throws IOException, ClassNotFoundException
+ {
+ return readObject(false);
+ }
+
+ /**
+ * Returns the next deserialized object read from the underlying stream.
+ *
+ * This method can be overriden by a class by implementing
+ * <code>private void readObject (ObjectInputStream)</code>.
+ *
+ * If an exception is thrown from this method, the stream is left in
+ * an undefined state. This method can also throw Errors and
+ * RuntimeExceptions if caused by existing readResolve() user code.
+ *
+ * @param shared true if handles created by this call should be shared
+ * with later calls.
+ * @return The object read from the underlying stream.
+ *
+ * @exception ClassNotFoundException The class that an object being
+ * read in belongs to cannot be found.
+ *
+ * @exception IOException Exception from underlying
+ * <code>InputStream</code>.
+ */
+ private final Object readObject(boolean shared)
+ throws ClassNotFoundException, IOException
+ {
if (this.useSubclassMethod)
return readObjectOverride();
@@ -146,7 +212,7 @@ public class ObjectInputStream extends InputStream
try
{
- ret_val = parseContent(marker);
+ ret_val = parseContent(marker, shared);
}
finally
{
@@ -163,13 +229,15 @@ public class ObjectInputStream extends InputStream
* byte indicating its type.
*
* @param marker the byte marker.
+ * @param shared true if handles created by this call should be shared
+ * with later calls.
* @return an object which represents the parsed content.
* @throws ClassNotFoundException if the class of an object being
* read in cannot be found.
* @throws IOException if invalid data occurs or one is thrown by the
* underlying <code>InputStream</code>.
*/
- private Object parseContent(byte marker)
+ private Object parseContent(byte marker, boolean shared)
throws ClassNotFoundException, IOException
{
Object ret_val;
@@ -207,6 +275,9 @@ public class ObjectInputStream extends InputStream
int oid = realInputStream.readInt();
if(dump) dumpElementln(Integer.toHexString(oid));
ret_val = lookupHandle(oid);
+ if (!shared)
+ throw new
+ InvalidObjectException("References can not be read unshared.");
break;
}
@@ -215,7 +286,7 @@ public class ObjectInputStream extends InputStream
if(dump) dumpElementln("CLASS");
ObjectStreamClass osc = (ObjectStreamClass)readObject();
Class clazz = osc.forClass();
- assignNewHandle(clazz);
+ assignNewHandle(clazz,shared);
ret_val = clazz;
break;
}
@@ -229,7 +300,7 @@ public class ObjectInputStream extends InputStream
// TC_PROXYCLASSDESC newHandle proxyClassDescInfo
// i.e. we have to assign the handle immediately after
// reading the marker.
- int handle = assignNewHandle("Dummy proxy");
+ int handle = assignNewHandle("Dummy proxy",shared);
/* END GCJ LOCAL */
int n_intf = this.realInputStream.readInt();
@@ -260,7 +331,7 @@ public class ObjectInputStream extends InputStream
}
}
/* GCJ LOCAL */
- rememberHandle(osc,handle);
+ rememberHandle(osc,shared,handle);
/* END GCJ LOCAL */
if (!is_consumed)
@@ -301,7 +372,8 @@ public class ObjectInputStream extends InputStream
if(dump) dumpElement("STRING=");
String s = this.realInputStream.readUTF();
if(dump) dumpElementln(s);
- ret_val = processResolution(null, s, assignNewHandle(s));
+ ret_val = processResolution(null, s, assignNewHandle(s,shared),
+ shared);
break;
}
@@ -314,12 +386,12 @@ public class ObjectInputStream extends InputStream
int length = this.realInputStream.readInt();
if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
Object array = Array.newInstance(componentType, length);
- int handle = assignNewHandle(array);
+ int handle = assignNewHandle(array,shared);
readArrayElements(array, componentType);
if(dump)
for (int i = 0, len = Array.getLength(array); i < len; i++)
dumpElementln(" ELEMENT[" + i + "]=", Array.get(array, i));
- ret_val = processResolution(null, array, handle);
+ ret_val = processResolution(null, array, handle, shared);
break;
}
@@ -337,7 +409,7 @@ public class ObjectInputStream extends InputStream
{
Externalizable obj = osc.newInstance();
- int handle = assignNewHandle(obj);
+ int handle = assignNewHandle(obj,shared);
boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
@@ -355,14 +427,14 @@ public class ObjectInputStream extends InputStream
throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
}
- ret_val = processResolution(osc, obj, handle);
+ ret_val = processResolution(osc, obj, handle,shared);
break;
} // end if (osc.realClassIsExternalizable)
Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
- int handle = assignNewHandle(obj);
+ int handle = assignNewHandle(obj,shared);
Object prevObject = this.currentObject;
ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
TreeSet<ValidatorAndPriority> prevObjectValidators =
@@ -404,7 +476,7 @@ public class ObjectInputStream extends InputStream
byte writeMarker = this.realInputStream.readByte();
while (writeMarker != TC_ENDBLOCKDATA)
{
- parseContent(writeMarker);
+ parseContent(writeMarker, shared);
writeMarker = this.realInputStream.readByte();
}
if(dump) dumpElementln("yes");
@@ -419,7 +491,7 @@ public class ObjectInputStream extends InputStream
this.currentObject = prevObject;
this.currentObjectStreamClass = prevObjectStreamClass;
- ret_val = processResolution(osc, obj, handle);
+ ret_val = processResolution(osc, obj, handle, shared);
if (currentObjectValidators != null)
invokeValidators();
this.currentObjectValidators = prevObjectValidators;
@@ -453,7 +525,7 @@ public class ObjectInputStream extends InputStream
dumpElementln("CONSTANT NAME = " + constantName);
Class clazz = osc.forClass();
Enum instance = Enum.valueOf(clazz, constantName);
- assignNewHandle(instance);
+ assignNewHandle(instance,shared);
ret_val = instance;
break;
}
@@ -554,7 +626,7 @@ public class ObjectInputStream extends InputStream
ObjectStreamField[] fields = new ObjectStreamField[field_count];
ObjectStreamClass osc = new ObjectStreamClass(name, uid,
flags, fields);
- assignNewHandle(osc);
+ assignNewHandle(osc,true);
for (int i = 0; i < field_count; i++)
{
@@ -1555,13 +1627,15 @@ public class ObjectInputStream extends InputStream
* Assigns the next available handle to <code>obj</code>.
*
* @param obj The object for which we want a new handle.
+ * @param shared True if the handle should be shared
+ * with later calls.
* @return A valid handle for the specified object.
*/
- private int assignNewHandle(Object obj)
+ private int assignNewHandle(Object obj, boolean shared)
{
int handle = this.nextOID;
this.nextOID = handle + 1;
- rememberHandle(obj,handle);
+ rememberHandle(obj,shared,handle);
return handle;
}
@@ -1569,40 +1643,44 @@ public class ObjectInputStream extends InputStream
* Remember the object associated with the given handle.
*
* @param obj an object
- *
+ * @param shared true if the reference should be shared
+ * with later calls.
* @param handle a handle, must be >= baseWireHandle
*
* @see #lookupHandle
*/
- private void rememberHandle(Object obj, int handle)
+ private void rememberHandle(Object obj, boolean shared,
+ int handle)
{
- Vector olt = this.objectLookupTable;
- handle = handle - baseWireHandle;
-
- if (olt.size() <= handle)
- olt.setSize(handle + 1);
-
- olt.set(handle, obj);
+ handles.put(handle, new Pair<Boolean,Object>(shared, obj));
}
/**
* Look up the object associated with a given handle.
*
* @param handle a handle, must be >= baseWireHandle
- *
* @return the object remembered for handle or null if none.
- *
+ * @throws StreamCorruptedException if the handle is invalid.
+ * @throws InvalidObjectException if the reference is not shared.
* @see #rememberHandle
*/
private Object lookupHandle(int handle)
+ throws ObjectStreamException
{
- Vector olt = this.objectLookupTable;
- handle = handle - baseWireHandle;
- Object result = handle < olt.size() ? olt.get(handle) : null;
- return result;
+ Pair<Boolean,Object> result = handles.get(handle);
+ if (result == null)
+ throw new StreamCorruptedException("The handle, " +
+ Integer.toHexString(handle) +
+ ", is invalid.");
+ if (!result.getLeft())
+ throw new InvalidObjectException("The handle, " +
+ Integer.toHexString(handle) +
+ ", is not shared.");
+ return result.getRight();
}
- private Object processResolution(ObjectStreamClass osc, Object obj, int handle)
+ private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
+ boolean shared)
throws IOException
{
if (osc != null && obj instanceof Serializable)
@@ -1633,13 +1711,34 @@ public class ObjectInputStream extends InputStream
if (this.resolveEnabled)
obj = resolveObject(obj);
- rememberHandle(obj, handle);
+ rememberHandle(obj, shared, handle);
+ if (!shared)
+ {
+ if (obj instanceof byte[])
+ return ((byte[]) obj).clone();
+ if (obj instanceof short[])
+ return ((short[]) obj).clone();
+ if (obj instanceof int[])
+ return ((int[]) obj).clone();
+ if (obj instanceof long[])
+ return ((long[]) obj).clone();
+ if (obj instanceof char[])
+ return ((char[]) obj).clone();
+ if (obj instanceof boolean[])
+ return ((boolean[]) obj).clone();
+ if (obj instanceof float[])
+ return ((float[]) obj).clone();
+ if (obj instanceof double[])
+ return ((double[]) obj).clone();
+ if (obj instanceof Object[])
+ return ((Object[]) obj).clone();
+ }
return obj;
}
private void clearHandles()
{
- this.objectLookupTable.clear();
+ handles.clear();
this.nextOID = baseWireHandle;
}
@@ -1966,7 +2065,7 @@ public class ObjectInputStream extends InputStream
private boolean useSubclassMethod;
private int nextOID;
private boolean resolveEnabled;
- private Vector<Object> objectLookupTable;
+ private Map<Integer,Pair<Boolean,Object>> handles;
private Object currentObject;
private ObjectStreamClass currentObjectStreamClass;
private TreeSet<ValidatorAndPriority> currentObjectValidators;
diff --git a/libjava/classpath/java/io/ObjectOutputStream.java b/libjava/classpath/java/io/ObjectOutputStream.java
index 316b9070133..b1894b36882 100644
--- a/libjava/classpath/java/io/ObjectOutputStream.java
+++ b/libjava/classpath/java/io/ObjectOutputStream.java
@@ -170,6 +170,7 @@ public class ObjectOutputStream extends OutputStream
* If an exception is thrown from this method, the stream is left in
* an undefined state.
*
+ * @param obj the object to serialize.
* @exception NotSerializableException An attempt was made to
* serialize an <code>Object</code> that is not serializable.
*
@@ -178,9 +179,71 @@ public class ObjectOutputStream extends OutputStream
*
* @exception IOException Exception from underlying
* <code>OutputStream</code>.
+ * @see #writeUnshared(Object)
*/
public final void writeObject(Object obj) throws IOException
{
+ writeObject(obj, true);
+ }
+
+ /**
+ * Writes an object to the stream in the same manner as
+ * {@link #writeObject(Object)}, but without the use of
+ * references. As a result, the object is always written
+ * to the stream in full. Likewise, if an object is written
+ * by this method and is then later written again by
+ * {@link #writeObject(Object)}, both calls will write out
+ * the object in full, as the later call to
+ * {@link #writeObject(Object)} will know nothing of the
+ * earlier use of {@link #writeUnshared(Object)}.
+ *
+ * @param obj the object to serialize.
+ * @throws NotSerializableException if the object being
+ * serialized does not implement
+ * {@link Serializable}.
+ * @throws InvalidClassException if a problem occurs with
+ * the class of the object being
+ * serialized.
+ * @throws IOException if an I/O error occurs on the underlying
+ * <code>OutputStream</code>.
+ * @since 1.4
+ * @see #writeObject(Object)
+ */
+ public void writeUnshared(Object obj)
+ throws IOException
+ {
+ writeObject(obj, false);
+ }
+
+ /**
+ * Writes a representation of <code>obj</code> to the underlying
+ * output stream by writing out information about its class, then
+ * writing out each of the objects non-transient, non-static
+ * fields. If any of these fields are other objects,
+ * they are written out in the same manner.
+ *
+ * This method can be overriden by a class by implementing
+ * <code>private void writeObject (ObjectOutputStream)</code>.
+ *
+ * If an exception is thrown from this method, the stream is left in
+ * an undefined state.
+ *
+ * @param obj the object to serialize.
+ * @param shared true if the serialized object should be
+ * shared with later calls.
+ * @exception NotSerializableException An attempt was made to
+ * serialize an <code>Object</code> that is not serializable.
+ *
+ * @exception InvalidClassException Somebody tried to serialize
+ * an object which is wrongly formatted.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ * @see #writeUnshared(Object)
+ */
+ private final void writeObject(Object obj, boolean shared)
+ throws IOException
+ {
if (useSubclassMethod)
{
if (dump)
@@ -212,7 +275,7 @@ public class ObjectOutputStream extends OutputStream
}
int handle = findHandle(obj);
- if (handle >= 0)
+ if (handle >= 0 && shared)
{
realOutput.writeByte(TC_REFERENCE);
realOutput.writeInt(handle);
@@ -243,7 +306,8 @@ public class ObjectOutputStream extends OutputStream
writeObject(osc.getSuper());
}
- assignNewHandle(obj);
+ if (shared)
+ assignNewHandle(obj);
break;
}
@@ -263,7 +327,8 @@ public class ObjectOutputStream extends OutputStream
/* TC_ENUM classDesc newHandle enumConstantName */
realOutput.writeByte(TC_ENUM);
writeObject(osc);
- assignNewHandle(obj);
+ if (shared)
+ assignNewHandle(obj);
writeObject(((Enum) obj).name());
break;
}
@@ -299,7 +364,8 @@ public class ObjectOutputStream extends OutputStream
if (obj instanceof String)
{
realOutput.writeByte(TC_STRING);
- assignNewHandle(obj);
+ if (shared)
+ assignNewHandle(obj);
realOutput.writeUTF((String)obj);
break;
}
@@ -308,7 +374,8 @@ public class ObjectOutputStream extends OutputStream
{
realOutput.writeByte(TC_ARRAY);
writeObject(osc);
- assignNewHandle(obj);
+ if (shared)
+ assignNewHandle(obj);
writeArraySizeAndElements(obj, clazz.getComponentType());
break;
}
@@ -316,11 +383,12 @@ public class ObjectOutputStream extends OutputStream
realOutput.writeByte(TC_OBJECT);
writeObject(osc);
- if (replaceDone)
- assignNewHandle(replacedObject);
- else
- assignNewHandle(obj);
-
+ if (shared)
+ if (replaceDone)
+ assignNewHandle(replacedObject);
+ else
+ assignNewHandle(obj);
+
if (obj instanceof Externalizable)
{
if (protocolVersion == PROTOCOL_VERSION_2)
diff --git a/libjava/classpath/java/io/StreamTokenizer.java b/libjava/classpath/java/io/StreamTokenizer.java
index b4695ab3d09..759aa9a2f05 100644
--- a/libjava/classpath/java/io/StreamTokenizer.java
+++ b/libjava/classpath/java/io/StreamTokenizer.java
@@ -330,6 +330,7 @@ public class StreamTokenizer
{
while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF)
;
+
if (ch != TT_EOF)
in.unread(ch);
return nextToken(); // Recursive, but not too deep in normal cases
@@ -431,6 +432,7 @@ public class StreamTokenizer
{
while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF)
;
+
if (ch != TT_EOF)
in.unread(ch);
return nextToken(); // Recursive, but not too deep in normal cases.
diff --git a/libjava/classpath/java/io/class-dependencies.conf b/libjava/classpath/java/io/class-dependencies.conf
deleted file mode 100644
index 633bb174941..00000000000
--- a/libjava/classpath/java/io/class-dependencies.conf
+++ /dev/null
@@ -1,100 +0,0 @@
-# This property file contains dependencies of classes, methods, and
-# field on other methods or classes.
-#
-# Syntax:
-#
-# <used>: <needed 1> [... <needed N>]
-#
-# means that when <used> is included, <needed 1> (... <needed N>) must
-# be included as well.
-#
-# <needed X> and <used> are of the form
-#
-# <class.methodOrField(signature)>
-#
-# or just
-#
-# <class>
-#
-# Within dependencies, variables can be used. A variable is defined as
-# follows:
-#
-# {variable}: value1 value2 ... value<n>
-#
-# variables can be used on the right side of dependencies as follows:
-#
-# <used>: com.bla.blu.{variable}.Class.m()V
-#
-# The use of the variable will expand to <n> dependencies of the form
-#
-# <used>: com.bla.blu.value1.Class.m()V
-# <used>: com.bla.blu.value2.Class.m()V
-# ...
-# <used>: com.bla.blu.value<n>.Class.m()V
-#
-# Variables can be redefined when building a system to select the
-# required support for features like encodings, protocols, etc.
-#
-# Hints:
-#
-# - For methods and fields, the signature is mandatory. For
-# specification, please see the Java Virtual Machine Specification by
-# SUN. Unlike in the spec, field signatures (types) are in brackets.
-#
-# - Package names must be separated by '/' (and not '.'). E.g.,
-# java/lang/Class (this is necessary, because the '.' is used to
-# separate method or field names from classes)
-#
-# - In case <needed> refers to a class, only the class itself will be
-# included in the resulting binary, NOT necessarily all its methods
-# and fields. If you want to refer to all methods and fields, you can
-# write class.* as an abbreviation.
-#
-# - Abbreviations for packages are also possible: my/package/* means all
-# methods and fields of all classes in my/package.
-#
-# - A line with a trailing '\' continues in the next line.
-
-java/io/File: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/io/IOException.<init>(Ljava/lang/String;)V \
- java/lang/IllegalArgumentException.<init>(Ljava/lang/String;)V
-
-java/io/FileDescriptor: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/lang/IllegalArgumentException.<init>(Ljava/lang/String;)V \
- java/io/IOException.<init>(Ljava/lang/String;)V
-
-java/io/FileInputStream: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/io/IOException.<init>(Ljava/lang/String;)V \
- java/io/FileNotFoundException.<init>(Ljava/lang/String;)V
-
-java/io/FileOutputStream: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/io/FileNotFoundException.<init>(Ljava/lang/String;)V \
- java/io/IOException.<init>(Ljava/lang/String;)V
-
-java/io/ObjectInputStream: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/lang/SecurityManager.currentClassLoader()Ljava/lang/ClassLoader; \
- java/lang/IllegalArgumentException.<init>(Ljava/lang/String;)V
-
-java/io/ObjectOutputStream: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/lang/SecurityManager.currentClassLoader()Ljava/lang/ClassLoader; \
- java/lang/IllegalArgumentException.<init>(Ljava/lang/String;)V
-
-java/io/RandomAccessFile: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/io/FileNotFoundException.<init>(Ljava/lang/String;)V \
- java/io/IOException.<init>(Ljava/lang/String;)V
-
-# end of file
diff --git a/libjava/classpath/java/lang/Character.java b/libjava/classpath/java/lang/Character.java
index b9c6f24e79f..506033f31bc 100644
--- a/libjava/classpath/java/lang/Character.java
+++ b/libjava/classpath/java/lang/Character.java
@@ -156,7 +156,7 @@ public final class Character implements Serializable, Comparable<Character>
private final String canonicalName;
/** Enumeration for the <code>forName()</code> method */
- private enum NameType { CANONICAL, NO_SPACES, CONSTANT; };
+ private enum NameType { CANONICAL, NO_SPACES, CONSTANT; }
/**
* Constructor for strictly defined blocks.
diff --git a/libjava/classpath/java/lang/Class.java b/libjava/classpath/java/lang/Class.java
index f44782f9692..d3df881367c 100644
--- a/libjava/classpath/java/lang/Class.java
+++ b/libjava/classpath/java/lang/Class.java
@@ -45,6 +45,7 @@ import java.io.InputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
+import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -1126,15 +1127,7 @@ public final class Class<T>
if (!Modifier.isPublic(constructor.getModifiers())
|| !Modifier.isPublic(VMClass.getModifiers(this, true)))
{
- final Constructor finalConstructor = constructor;
- AccessController.doPrivileged(new PrivilegedAction()
- {
- public Object run()
- {
- finalConstructor.setAccessible(true);
- return null;
- }
- });
+ setAccessible(constructor);
}
synchronized(this)
{
@@ -1397,7 +1390,9 @@ public final class Class<T>
{
try
{
- return (T[]) getMethod("values").invoke(null);
+ Method m = getMethod("values");
+ setAccessible(m);
+ return (T[]) m.invoke(null);
}
catch (NoSuchMethodException exception)
{
@@ -1787,5 +1782,18 @@ public final class Class<T>
return VMClass.isMemberClass(this);
}
-
+ /**
+ * Utility method for use by classes in this package.
+ */
+ static void setAccessible(final AccessibleObject obj)
+ {
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ obj.setAccessible(true);
+ return null;
+ }
+ });
+ }
}
diff --git a/libjava/classpath/java/lang/Enum.java b/libjava/classpath/java/lang/Enum.java
index f141619be4d..fa217bb67a6 100644
--- a/libjava/classpath/java/lang/Enum.java
+++ b/libjava/classpath/java/lang/Enum.java
@@ -97,9 +97,12 @@ public abstract class Enum<T extends Enum<T>>
try
{
+ // XXX We should not use getDeclaredField, because it does
+ // an unnecessary security check.
Field f = etype.getDeclaredField(s);
if (! f.isEnumConstant())
throw new IllegalArgumentException(s);
+ Class.setAccessible(f);
return (S) f.get(null);
}
catch (NoSuchFieldException exception)
@@ -220,4 +223,14 @@ public abstract class Enum<T extends Enum<T>>
k = k.getSuperclass();
return k;
}
+
+ /**
+ * Enumerations can not have finalization methods.
+ *
+ * @since 1.6
+ */
+ protected final void finalize()
+ {
+ }
+
}
diff --git a/libjava/classpath/java/lang/StrictMath.java b/libjava/classpath/java/lang/StrictMath.java
index ec74ca4133b..6eb1cb20859 100644
--- a/libjava/classpath/java/lang/StrictMath.java
+++ b/libjava/classpath/java/lang/StrictMath.java
@@ -2278,8 +2278,9 @@ public final strictfp class StrictMath
j |= iq[i];
if (j == 0) // Need recomputation.
{
- int k;
- for (k = 1; iq[jk - k] == 0; k++); // k = no. of terms needed.
+ int k; // k = no. of terms needed.
+ for (k = 1; iq[jk - k] == 0; k++)
+ ;
for (i = jz + 1; i <= jz + k; i++) // Add q[jz+1] to q[jz+k].
{
diff --git a/libjava/classpath/java/lang/String.java b/libjava/classpath/java/lang/String.java
index 28b77c0aa56..ecb46881148 100644
--- a/libjava/classpath/java/lang/String.java
+++ b/libjava/classpath/java/lang/String.java
@@ -1592,8 +1592,10 @@ public final class String
if (begin == limit)
return "";
while (value[begin++] <= '\u0020');
+
int end = limit;
- while (value[--end] <= '\u0020');
+ while (value[--end] <= '\u0020')
+ ;
return substring(begin - offset - 1, end - offset + 1);
}
@@ -1988,4 +1990,17 @@ public final class String
return Character.offsetByCodePoints(value, offset, count, offset + index,
codePointOffset);
}
+
+ /**
+ * Returns true if, and only if, {@link #length()}
+ * is <code>0</code>.
+ *
+ * @return true if the length of the string is zero.
+ * @since 1.6
+ */
+ public boolean isEmpty()
+ {
+ return count == 0;
+ }
+
}
diff --git a/libjava/classpath/java/lang/System.java b/libjava/classpath/java/lang/System.java
index ca390bf161b..68d76fc2164 100644
--- a/libjava/classpath/java/lang/System.java
+++ b/libjava/classpath/java/lang/System.java
@@ -1,5 +1,5 @@
/* System.java -- useful methods to interface with the system
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,8 +42,11 @@ package java.lang;
import gnu.classpath.SystemProperties;
import gnu.classpath.VMStackWalker;
+import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
+import java.nio.channels.Channel;
+import java.nio.channels.spi.SelectorProvider;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Collections;
@@ -362,6 +365,7 @@ public final class System
* <dt>gnu.java.io.encoding_scheme_alias.iso-latin-_?</dt> <dd>8859_?</dd>
* <dt>gnu.java.io.encoding_scheme_alias.latin?</dt> <dd>8859_?</dd>
* <dt>gnu.java.io.encoding_scheme_alias.utf-8</dt> <dd>UTF8</dd>
+ * <dt>gnu.java.util.zoneinfo.dir</dt> <dd>Root of zoneinfo tree</dd>
* <dt>gnu.javax.print.server</dt> <dd>Hostname of external CUPS server.</dd>
* </dl>
*
@@ -671,6 +675,25 @@ public final class System
return VMRuntime.mapLibraryName(libname);
}
+ /**
+ * Returns the inherited channel of the VM.
+ *
+ * This wraps the inheritedChannel() call of the system's default
+ * {@link SelectorProvider}.
+ *
+ * @return the inherited channel of the VM
+ *
+ * @throws IOException If an I/O error occurs
+ * @throws SecurityException If an installed security manager denies access
+ * to RuntimePermission("inheritedChannel")
+ *
+ * @since 1.5
+ */
+ public static Channel inheritedChannel()
+ throws IOException
+ {
+ return SelectorProvider.provider().inheritedChannel();
+ }
/**
* This is a specialised <code>Collection</code>, providing
diff --git a/libjava/classpath/java/lang/class-dependencies.conf b/libjava/classpath/java/lang/class-dependencies.conf
deleted file mode 100644
index 4fbf75eb1ce..00000000000
--- a/libjava/classpath/java/lang/class-dependencies.conf
+++ /dev/null
@@ -1,58 +0,0 @@
-# This property file contains dependencies of classes, methods, and
-# field on other methods or classes.
-#
-# Syntax:
-#
-# <used>: <needed 1> [... <needed N>]
-#
-# means that when <used> is included, <needed 1> (... <needed N>) must
-# be included as well.
-#
-# <needed X> and <used> are of the form
-#
-# <class.methodOrField(signature)>
-#
-# or just
-#
-# <class>
-#
-# Within dependencies, variables can be used. A variable is defined as
-# follows:
-#
-# {variable}: value1 value2 ... value<n>
-#
-# variables can be used on the right side of dependencies as follows:
-#
-# <used>: com.bla.blu.{variable}.Class.m()V
-#
-# The use of the variable will expand to <n> dependencies of the form
-#
-# <used>: com.bla.blu.value1.Class.m()V
-# <used>: com.bla.blu.value2.Class.m()V
-# ...
-# <used>: com.bla.blu.value<n>.Class.m()V
-#
-# Variables can be redefined when building a system to select the
-# required support for features like encodings, protocols, etc.
-#
-# Hints:
-#
-# - For methods and fields, the signature is mandatory. For
-# specification, please see the Java Virtual Machine Specification by
-# SUN. Unlike in the spec, field signatures (types) are in brackets.
-#
-# - Package names must be separated by '/' (and not '.'). E.g.,
-# java/lang/Class (this is necessary, because the '.' is used to
-# separate method or field names from classes)
-#
-# - In case <needed> refers to a class, only the class itself will be
-# included in the resulting binary, NOT necessarily all its methods
-# and fields. If you want to refer to all methods and fields, you can
-# write class.* as an abbreviation.
-#
-# - Abbreviations for packages are also possible: my/package/* means all
-# methods and fields of all classes in my/package.
-#
-# - A line with a trailing '\' continues in the next line.
-
-# end of file
diff --git a/libjava/classpath/java/lang/management/LockInfo.java b/libjava/classpath/java/lang/management/LockInfo.java
new file mode 100644
index 00000000000..ae5166834ca
--- /dev/null
+++ b/libjava/classpath/java/lang/management/LockInfo.java
@@ -0,0 +1,114 @@
+/* LockInfo.java - Information on a lock.
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.lang.management;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * Provides information on a lock held by a thread.
+ * A lock can be either a built-in monitor, an
+ * <emph>ownable synchronizer</emph> (i.e. a subclass
+ * of {@link java.util.concurrent.locks.AbstractOwnableSynchronizer}),
+ * or a {@link java.util.concurrent.locks.Condition}
+ * object.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public class LockInfo
+{
+
+ /**
+ * The class name of the lock object.
+ */
+ private String className;
+
+ /**
+ * The identity hash code of the lock object.
+ */
+ private int identityHashCode;
+
+ /**
+ * Constructs a new {@link LockInfo} object with the
+ * specified class name and identity hash code.
+ *
+ * @param className the name of the class of the lock object.
+ * @param identityHashCode the identity hash code of the
+ * lock object.
+ */
+ @ConstructorProperties({"className","identityHashCode"})
+ public LockInfo(String className, int identityHashCode)
+ {
+ this.className = className;
+ this.identityHashCode = identityHashCode;
+ }
+
+ /**
+ * Returns the class name of the lock object.
+ *
+ * @return the class name of the lock object.
+ */
+ public String getClassName()
+ {
+ return className;
+ }
+
+ /**
+ * Returns the identity hash code of the lock object.
+ *
+ * @return the identity hash code of the lock object.
+ */
+ public int getIdentityHashCode()
+ {
+ return identityHashCode;
+ }
+
+ /**
+ * Returns a textual representation of the lock,
+ * constructed by concatenating the class name,
+ * <code>'@'</code> and the identity hash code
+ * in unsigned hexadecimal form.
+ *
+ * @return a textual representation of the lock.
+ */
+ public String toString()
+ {
+ return className + '@' + Integer.toHexString(identityHashCode);
+ }
+
+}
diff --git a/libjava/classpath/java/lang/management/ManagementFactory.java b/libjava/classpath/java/lang/management/ManagementFactory.java
index a51ca0f4c9f..977b3997535 100644
--- a/libjava/classpath/java/lang/management/ManagementFactory.java
+++ b/libjava/classpath/java/lang/management/ManagementFactory.java
@@ -49,20 +49,36 @@ import gnu.java.lang.management.MemoryPoolMXBeanImpl;
import gnu.java.lang.management.RuntimeMXBeanImpl;
import gnu.java.lang.management.ThreadMXBeanImpl;
+import java.io.IOException;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.logging.LogManager;
+import javax.management.Attribute;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
/**
* <p>
* Provides access to the system's management beans via a series
@@ -549,4 +565,253 @@ public class ManagementFactory
return platformServer;
}
+ /**
+ * <p>
+ * Returns a proxy for the specified platform bean. A proxy object is created
+ * using <code>Proxy.newProxyInstance(mxbeanInterface.getClassLoader(),
+ * new Class[] { mxbeanInterface }, handler)</code>. The
+ * {@link javax.management.NotificationEmitter} class is also added to the
+ * array if the bean provides notifications. <code>handler</code> refers
+ * to the invocation handler which forwards calls to the connection, and
+ * also provides translation between the Java data types used in the
+ * bean interfaces and the open data types, as specified in the description
+ * of this class. It is this translation that makes the
+ * usual {@link javax.management.MBeanServerInvocationHandler} inappropriate
+ * for providing such a proxy.
+ * </p>
+ * <p>
+ * <strong>Note</strong>: use of the proxy may result in
+ * {@link java.io.IOException}s from the underlying {@link MBeanServerConnection}
+ * and a {@link java.io.InvalidObjectException} if enum constants
+ * used on the client and the server don't match.
+ * </p>
+ *
+ * @param connection the server connection to use to access the bean.
+ * @param mxbeanName the {@link javax.management.ObjectName} of the
+ * bean to provide a proxy for.
+ * @param mxbeanInterface the interface for the bean being proxied.
+ * @return a proxy for the specified bean.
+ * @throws IllegalArgumentException if <code>mxbeanName</code> is not a valid
+ * {@link javax.management.ObjectName},
+ * the interface and name do not match the
+ * same bean, the name does not refer to a
+ * platform bean or the bean is not registered
+ * with the server accessed by <code>connection</code>.
+ * @throws IOException if the connection throws one.
+ */
+ public static <T> T newPlatformMXBeanProxy(MBeanServerConnection connection,
+ String mxbeanName,
+ Class<T> mxbeanInterface)
+ throws IOException
+ {
+ if (!(mxbeanName.equals(CLASS_LOADING_MXBEAN_NAME) ||
+ mxbeanName.equals(COMPILATION_MXBEAN_NAME) ||
+ mxbeanName.startsWith(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE) ||
+ mxbeanName.startsWith(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE) ||
+ mxbeanName.equals(MEMORY_MXBEAN_NAME) ||
+ mxbeanName.startsWith(MEMORY_POOL_MXBEAN_DOMAIN_TYPE) ||
+ mxbeanName.equals(OPERATING_SYSTEM_MXBEAN_NAME) ||
+ mxbeanName.equals(RUNTIME_MXBEAN_NAME) ||
+ mxbeanName.equals(THREAD_MXBEAN_NAME)))
+ {
+ throw new IllegalArgumentException("The named bean, " + mxbeanName +
+ ", is not a platform name.");
+ }
+ if ((mxbeanName.equals(CLASS_LOADING_MXBEAN_NAME) &&
+ mxbeanInterface != ClassLoadingMXBean.class) ||
+ (mxbeanName.equals(COMPILATION_MXBEAN_NAME) &&
+ mxbeanInterface != CompilationMXBean.class) ||
+ (mxbeanName.startsWith(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE) &&
+ mxbeanInterface != GarbageCollectorMXBean.class) ||
+ (mxbeanName.startsWith(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE) &&
+ mxbeanInterface != MemoryManagerMXBean.class) ||
+ (mxbeanName.equals(MEMORY_MXBEAN_NAME) &&
+ mxbeanInterface != MemoryMXBean.class) ||
+ (mxbeanName.startsWith(MEMORY_POOL_MXBEAN_DOMAIN_TYPE) &&
+ mxbeanInterface != MemoryPoolMXBean.class) ||
+ (mxbeanName.equals(OPERATING_SYSTEM_MXBEAN_NAME) &&
+ mxbeanInterface != OperatingSystemMXBean.class) ||
+ (mxbeanName.equals(RUNTIME_MXBEAN_NAME) &&
+ mxbeanInterface != RuntimeMXBean.class) ||
+ (mxbeanName.equals(THREAD_MXBEAN_NAME) &&
+ mxbeanInterface != ThreadMXBean.class))
+ throw new IllegalArgumentException("The interface, " + mxbeanInterface +
+ ", does not match the bean, " + mxbeanName);
+ ObjectName bean;
+ try
+ {
+ bean = new ObjectName(mxbeanName);
+ }
+ catch (MalformedObjectNameException e)
+ {
+ throw new IllegalArgumentException("The named bean is invalid.");
+ }
+ if (!(connection.isRegistered(bean)))
+ throw new IllegalArgumentException("The bean is not registered on this connection.");
+ Class[] interfaces;
+ if (mxbeanName.equals(MEMORY_MXBEAN_NAME))
+ interfaces = new Class[] { mxbeanInterface, NotificationEmitter.class };
+ else
+ interfaces = new Class[] { mxbeanInterface };
+ return (T) Proxy.newProxyInstance(mxbeanInterface.getClassLoader(),
+ interfaces,
+ new ManagementInvocationHandler(connection, bean));
+ }
+
+ /**
+ * This invocation handler provides method calls for a platform bean
+ * by forwarding them to a {@link MBeanServerConnection}. Translation from
+ * Java data types to open data types is performed as specified above.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+ private static class ManagementInvocationHandler
+ implements InvocationHandler
+ {
+
+ /**
+ * The encapsulated connection.
+ */
+ private MBeanServerConnection conn;
+
+ /**
+ * The bean being proxied.
+ */
+ private ObjectName bean;
+
+ /**
+ * Constructs a new {@link InvocationHandler} which proxies
+ * for the specified bean using the supplied connection.
+ *
+ * @param conn the connection on which to forward method calls.
+ * @param bean the bean to proxy.
+ */
+ public ManagementInvocationHandler(MBeanServerConnection conn,
+ ObjectName bean)
+ throws IOException
+ {
+ this.conn = conn;
+ this.bean = bean;
+ }
+
+ /**
+ * Called by the proxy class whenever a method is called. The method
+ * is emulated by retrieving an attribute from, setting an attribute on
+ * or invoking a method on the server connection as required. Translation
+ * between the Java data types supplied as arguments to the open types used
+ * by the bean is provided, as well as translation of the return value back
+ * in to the appropriate Java type.
+ *
+ * @param proxy the proxy on which the method was called.
+ * @param method the method which was called.
+ * @param args the arguments supplied to the method.
+ * @return the return value from the method.
+ * @throws Throwable if an exception is thrown in performing the
+ * method emulation.
+ */
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable
+ {
+ String name = method.getName();
+ if (name.equals("toString"))
+ return "Proxy for " + bean + " using " + conn;
+ if (name.equals("addNotificationListener"))
+ {
+ conn.addNotificationListener(bean,
+ (NotificationListener) args[0],
+ (NotificationFilter) args[1],
+ args[2]);
+ return null;
+ }
+ if (name.equals("getNotificationInfo"))
+ return conn.getMBeanInfo(bean).getNotifications();
+ if (name.equals("removeNotificationListener"))
+ {
+ if (args.length == 1)
+ conn.removeNotificationListener(bean,
+ (NotificationListener)
+ args[0]);
+ else
+ conn.removeNotificationListener(bean,
+ (NotificationListener)
+ args[0],
+ (NotificationFilter)
+ args[1], args[2]);
+ return null;
+ }
+ String attrib = null;
+ if (name.startsWith("get"))
+ attrib = name.substring(3);
+ else if (name.startsWith("is"))
+ attrib = name.substring(2);
+ if (attrib != null)
+ return translate(conn.getAttribute(bean, attrib), method);
+ else if (name.startsWith("set"))
+ {
+ conn.setAttribute(bean, new Attribute(name.substring(3),
+ args[0]));
+ return null;
+ }
+ else
+ return translate(conn.invoke(bean, name, args, null), method);
+ }
+
+ /**
+ * Translates the returned open data type to the value
+ * required by the interface.
+ *
+ * @param otype the open type returned by the method call.
+ * @param method the method that was called.
+ * @return the equivalent return type required by the interface.
+ * @throws Throwable if an exception is thrown in performing the
+ * conversion.
+ */
+ private final Object translate(Object otype, Method method)
+ throws Throwable
+ {
+ Class<?> returnType = method.getReturnType();
+ if (returnType.isEnum())
+ {
+ String ename = (String) otype;
+ Enum[] constants = (Enum[]) returnType.getEnumConstants();
+ for (Enum c : constants)
+ if (c.name().equals(ename))
+ return c;
+ }
+ if (List.class.isAssignableFrom(returnType))
+ {
+ Object[] elems = (Object[]) otype;
+ List l = new ArrayList(elems.length);
+ for (Object elem : elems)
+ l.add(elem);
+ return l;
+ }
+ if (Map.class.isAssignableFrom(returnType))
+ {
+ TabularData data = (TabularData) otype;
+ Map m = new HashMap(data.size());
+ for (Object val : data.values())
+ {
+ CompositeData vals = (CompositeData) val;
+ m.put(vals.get("key"), vals.get("value"));
+ }
+ return m;
+ }
+ try
+ {
+ Method m = returnType.getMethod("from",
+ new Class[]
+ { CompositeData.class });
+ return m.invoke(null, (CompositeData) otype);
+ }
+ catch (NoSuchMethodException e)
+ {
+ /* Ignored; we expect this if this
+ isn't a from(CompositeData) class */
+ }
+ return otype;
+ }
+
+ }
}
diff --git a/libjava/classpath/java/lang/management/MemoryUsage.java b/libjava/classpath/java/lang/management/MemoryUsage.java
index 3c2a4cba6e9..d851da9a72e 100644
--- a/libjava/classpath/java/lang/management/MemoryUsage.java
+++ b/libjava/classpath/java/lang/management/MemoryUsage.java
@@ -180,14 +180,14 @@ public class MemoryUsage
if (data == null)
return null;
CompositeType type = data.getCompositeType();
- ThreadInfo.checkAttribute(type, "init", SimpleType.LONG);
- ThreadInfo.checkAttribute(type, "used", SimpleType.LONG);
- ThreadInfo.checkAttribute(type, "committed", SimpleType.LONG);
- ThreadInfo.checkAttribute(type, "max", SimpleType.LONG);
- return new MemoryUsage(((Long) data.get("init")).longValue(),
- ((Long) data.get("used")).longValue(),
- ((Long) data.get("committed")).longValue(),
- ((Long) data.get("max")).longValue());
+ ThreadInfo.checkAttribute(type, "Init", SimpleType.LONG);
+ ThreadInfo.checkAttribute(type, "Used", SimpleType.LONG);
+ ThreadInfo.checkAttribute(type, "Committed", SimpleType.LONG);
+ ThreadInfo.checkAttribute(type, "Max", SimpleType.LONG);
+ return new MemoryUsage(((Long) data.get("Init")).longValue(),
+ ((Long) data.get("Used")).longValue(),
+ ((Long) data.get("Committed")).longValue(),
+ ((Long) data.get("Max")).longValue());
}
/**
diff --git a/libjava/classpath/java/lang/management/MonitorInfo.java b/libjava/classpath/java/lang/management/MonitorInfo.java
new file mode 100644
index 00000000000..cba73a80de4
--- /dev/null
+++ b/libjava/classpath/java/lang/management/MonitorInfo.java
@@ -0,0 +1,179 @@
+/* MonitorInfo.java - Information on a monitor lock.
+ Copyright (C) 2006 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.lang.management;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.SimpleType;
+
+/**
+ * Provides information on a monitor lock held by a thread.
+ * A monitor lock is obtained when a thread enters a synchronized
+ * block or method.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public class MonitorInfo
+ extends LockInfo
+{
+
+ /**
+ * The stack depth at which the lock was obtained.
+ */
+ private int stackDepth;
+
+ /**
+ * The stack frame at which the lock was obtained.
+ */
+ private StackTraceElement stackFrame;
+
+ /**
+ * Constructs a new {@link MonitorInfo} using the specified
+ * lock class name and identity hash code, and the given
+ * stack depth and frame.
+ *
+ * @param className the class name of the lock object.
+ * @param identityHashCode the identity hash code of the lock object.
+ * @param stackDepth the depth of the stack at which the lock
+ * was obtained.
+ * @param stackFrame the frame of the stack at which the lock was
+ * obtained.
+ * @throws IllegalArgumentException if the stack depth and frame are
+ * inconsistent i.e. the frame is
+ * <code>null</code> but the depth is
+ * &ge; 0, or the frame is not
+ * <code>null</code> but the depth is
+ * &lt; 0.
+ */
+ public MonitorInfo(String className, int identityHashCode, int stackDepth,
+ StackTraceElement stackFrame)
+ {
+ super(className, identityHashCode);
+ if (stackFrame == null && stackDepth >= 0)
+ throw new IllegalArgumentException("The stack frame is null, but the " +
+ "stack depth is greater than or equal " +
+ "to zero.");
+ if (stackFrame != null && stackDepth < 0)
+ throw new IllegalArgumentException("The stack frame is not null, but the " +
+ "stack depth is less than zero.");
+ this.stackDepth = stackDepth;
+ this.stackFrame = stackFrame;
+ }
+
+ /**
+ * <p>
+ * Returns a {@link MonitorInfo} instance using the values
+ * given in the supplied
+ * {@link javax.management.openmbean.CompositeData} object.
+ * The composite data instance should contain the following
+ * attributes with the specified types:
+ * </p>
+ * <table>
+ * <th><td>Name</td><td>Type</td></th>
+ * <tr><td>className</td><td>java.lang.String</td></tr>
+ * <tr><td>identityHashCode</td><td>java.lang.Integer</td></tr>
+ * <tr><td>lockedStackDepth</td><td>java.lang.Integer</td></tr>
+ * <tr><td>lockedStackFrame</td><td>javax.management.openmbean.CompositeData
+ * </td></tr>
+ * </table>
+ * <p>
+ * The stack trace is further described as:
+ * </p>
+ * <table>
+ * <th><td>Name</td><td>Type</td></th>
+ * <tr><td>className</td><td>java.lang.String</td></tr>
+ * <tr><td>methodName</td><td>java.lang.String</td></tr>
+ * <tr><td>fileName</td><td>java.lang.String</td></tr>
+ * <tr><td>lineNumber</td><td>java.lang.Integer</td></tr>
+ * <tr><td>nativeMethod</td><td>java.lang.Boolean</td></tr>
+ * </table>
+ *
+ * @param data the composite data structure to take values from.
+ * @return a new instance containing the values from the
+ * composite data structure, or <code>null</code>
+ * if the data structure was also <code>null</code>.
+ * @throws IllegalArgumentException if the composite data structure
+ * does not match the structure
+ * outlined above.
+ */
+ public static MonitorInfo from(CompositeData data)
+ {
+ if (data == null)
+ return null;
+ CompositeType type = data.getCompositeType();
+ ThreadInfo.checkAttribute(type, "ClassName", SimpleType.STRING);
+ ThreadInfo.checkAttribute(type, "IdentityHashCode", SimpleType.INTEGER);
+ ThreadInfo.checkAttribute(type, "LockedStackDepth", SimpleType.INTEGER);
+ ThreadInfo.checkAttribute(type, "LockedStackFrame",
+ ThreadInfo.getStackTraceType());
+ CompositeData frame = (CompositeData) data.get("LockedStackFrame");
+ return new MonitorInfo((String) data.get("ClassName"),
+ (Integer) data.get("IdentityHashCode"),
+ (Integer) data.get("LockedStackDepth"),
+ new StackTraceElement((String) frame.get("ClassName"),
+ (String) frame.get("MethodName"),
+ (String) frame.get("FileName"),
+ (Integer) frame.get("LineNumber")));
+ }
+
+ /**
+ * Returns the depth of the stack at which the lock was obtained.
+ * This works as an index into the array returned by
+ * {@link ThreadInfo#getStackTrace()}.
+ *
+ * @return the depth of the stack at which the lock was obtained,
+ * or a negative number if this information is unavailable.
+ */
+ public int getLockedStackDepth()
+ {
+ return stackDepth;
+ }
+
+ /**
+ * Returns the stack frame at which the lock was obtained.
+ *
+ * @return the stack frame at which the lock was obtained,
+ * or <code>null</code> if this informati0on is unavailable.
+ */
+ public StackTraceElement getLockedStackFrame()
+ {
+ return stackFrame;
+ }
+
+}
diff --git a/libjava/classpath/java/lang/management/OperatingSystemMXBean.java b/libjava/classpath/java/lang/management/OperatingSystemMXBean.java
index 2430a9fbf5c..ed38285a560 100644
--- a/libjava/classpath/java/lang/management/OperatingSystemMXBean.java
+++ b/libjava/classpath/java/lang/management/OperatingSystemMXBean.java
@@ -87,6 +87,22 @@ public interface OperatingSystemMXBean
String getName();
/**
+ * Returns the system load average for the last minute, or -1
+ * if this is unavailable. The availability and calculation
+ * of the load average is system-dependent, but is usually
+ * a damped time-dependent average obtained by monitoring the
+ * number of queued and running processes. It is expected
+ * that this method will be called frequently to monitor the
+ * average over time, so it may not be implemented on systems
+ * where such a call is expensive.
+ *
+ * @return the system load average for the last minute, or -1
+ * if this is unavailable.
+ * @since 1.6
+ */
+ double getSystemLoadAverage();
+
+ /**
* Returns the version of the underlying operating system. This
* is equivalent to obtaining the <code>os.version</code> property
* via {@link System#getProperty(String)}.
diff --git a/libjava/classpath/java/lang/management/ThreadInfo.java b/libjava/classpath/java/lang/management/ThreadInfo.java
index 428aca3fac8..884f5af5e9e 100644
--- a/libjava/classpath/java/lang/management/ThreadInfo.java
+++ b/libjava/classpath/java/lang/management/ThreadInfo.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package java.lang.management;
+import java.util.Arrays;
+
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeType;
@@ -68,6 +70,8 @@ import javax.management.openmbean.SimpleType;
* monitor, upon which the thread described here is blocked.</li>
* <li>The stack trace of the thread (if requested on creation
* of this object</li>
+ * <li>The current locks held on object monitors by the thread.</li>
+ * <li>The current locks held on ownable synchronizers by the thread.</li>
* </ul>
* <li><strong>Synchronization Statistics</strong>
* <ul>
@@ -165,11 +169,28 @@ public class ThreadInfo
private StackTraceElement[] trace;
/**
+ * The array of information on monitors locked by the thread.
+ */
+ private MonitorInfo[] lockedMonitors;
+
+ /**
+ * The array of information on ownable synchronizers locked
+ * by the thread.
+ */
+ private LockInfo[] lockedSynchronizers;
+
+ /**
* Cache a local reference to the thread management bean.
*/
private static ThreadMXBean bean = null;
/**
+ * Cache the {@link javax.management.openmbean.CompositeType}
+ * for the {@link StackTraceElement}.
+ */
+ private static CompositeType seType;
+
+ /**
* Constructs a new {@link ThreadInfo} corresponding
* to the thread specified.
*
@@ -200,13 +221,57 @@ public class ThreadInfo
long waitedTime, boolean isInNative, boolean isSuspended,
StackTraceElement[] trace)
{
+ this(thread, blockedCount, blockedTime, lock, lockOwner, waitedCount,
+ waitedTime, isInNative, isSuspended, trace, new MonitorInfo[]{},
+ new LockInfo[]{});
+ }
+
+ /**
+ * Constructs a new {@link ThreadInfo} corresponding
+ * to the thread specified.
+ *
+ * @param thread the thread on which the new instance
+ * will be based.
+ * @param blockedCount the number of times the thread
+ * has been blocked.
+ * @param blockedTime the accumulated number of milliseconds
+ * the specified thread has been blocked
+ * (only used with contention monitoring enabled)
+ * @param lock the monitor lock the thread is waiting for
+ * (only used if blocked)
+ * @param lockOwner the thread which owns the monitor lock, or
+ * <code>null</code> if it doesn't have an owner
+ * (only used if blocked)
+ * @param waitedCount the number of times the thread has been in a
+ * waiting state.
+ * @param waitedTime the accumulated number of milliseconds the
+ * specified thread has been waiting
+ * (only used with contention monitoring enabled)
+ * @param isInNative true if the thread is in a native method.
+ * @param isSuspended true if the thread is suspended.
+ * @param trace the stack trace of the thread to a pre-determined
+ * depth (see VMThreadMXBeanImpl)
+ * @param lockedMonitors an array of {@link MonitorInfo} objects
+ * representing locks held on object monitors
+ * by the thread.
+ * @param lockedSynchronizers an array of {@link LockInfo} objects
+ * representing locks held on ownable
+ * synchronizers by the thread.
+ * @since 1.6
+ */
+ private ThreadInfo(Thread thread, long blockedCount, long blockedTime,
+ Object lock, Thread lockOwner, long waitedCount,
+ long waitedTime, boolean isInNative, boolean isSuspended,
+ StackTraceElement[] trace, MonitorInfo[] lockedMonitors,
+ LockInfo[] lockedSynchronizers)
+ {
this(thread.getId(), thread.getName(), thread.getState(), blockedCount, blockedTime,
lock == null ? null : lock.getClass().getName() + "@" +
Integer.toHexString(System.identityHashCode(lock)),
lockOwner == null ? -1 : lockOwner.getId(),
lockOwner == null ? null : lockOwner.getName(),
waitedCount, waitedTime, isInNative, isSuspended,
- trace);
+ trace, lockedMonitors, lockedSynchronizers);
}
/**
@@ -248,6 +313,59 @@ public class ThreadInfo
long waitedTime, boolean isInNative, boolean isSuspended,
StackTraceElement[] trace)
{
+ this(threadId, threadName, threadState, blockedCount, blockedTime,
+ lockName, lockOwnerId, lockOwnerName, waitedCount, waitedTime,
+ isInNative, isSuspended, trace, new MonitorInfo[]{}, new LockInfo[]{});
+ }
+
+ /**
+ * Constructs a new {@link ThreadInfo} corresponding
+ * to the thread details specified.
+ *
+ * @param threadId the id of the thread on which this
+ * new instance will be based.
+ * @param threadName the name of the thread on which
+ * this new instance will be based.
+ * @param threadState the state of the thread on which
+ * this new instance will be based.
+ * @param blockedCount the number of times the thread
+ * has been blocked.
+ * @param blockedTime the accumulated number of milliseconds
+ * the specified thread has been blocked
+ * (only used with contention monitoring enabled)
+ * @param lockName the name of the monitor lock the thread is waiting for
+ * (only used if blocked)
+ * @param lockOwnerId the id of the thread which owns the monitor
+ * lock, or <code>-1</code> if it doesn't have an owner
+ * (only used if blocked)
+ * @param lockOwnerName the name of the thread which owns the monitor
+ * lock, or <code>null</code> if it doesn't have an
+ * owner (only used if blocked)
+ * @param waitedCount the number of times the thread has been in a
+ * waiting state.
+ * @param waitedTime the accumulated number of milliseconds the
+ * specified thread has been waiting
+ * (only used with contention monitoring enabled)
+ * @param isInNative true if the thread is in a native method.
+ * @param isSuspended true if the thread is suspended.
+ * @param trace the stack trace of the thread to a pre-determined
+ * depth (see VMThreadMXBeanImpl)
+ * @param lockedMonitors an array of {@link MonitorInfo} objects
+ * representing locks held on object monitors
+ * by the thread.
+ * @param lockedSynchronizers an array of {@link LockInfo} objects
+ * representing locks held on ownable
+ * synchronizers by the thread.
+ *
+ * @since 1.6
+ */
+ private ThreadInfo(long threadId, String threadName, Thread.State threadState,
+ long blockedCount, long blockedTime, String lockName,
+ long lockOwnerId, String lockOwnerName, long waitedCount,
+ long waitedTime, boolean isInNative, boolean isSuspended,
+ StackTraceElement[] trace, MonitorInfo[] lockedMonitors,
+ LockInfo[] lockedSynchronizers)
+ {
this.threadId = threadId;
this.threadName = threadName;
this.threadState = threadState;
@@ -261,6 +379,8 @@ public class ThreadInfo
this.isInNative = isInNative;
this.isSuspended = isSuspended;
this.trace = trace;
+ this.lockedMonitors = lockedMonitors;
+ this.lockedSynchronizers = lockedSynchronizers;
}
/**
@@ -287,6 +407,44 @@ public class ThreadInfo
}
/**
+ * Returns the {@link javax.management.openmbean.CompositeType} for
+ * a {@link StackTraceElement}.
+ *
+ * @return the type for the stack trace element.
+ */
+ static CompositeType getStackTraceType()
+ {
+ if (seType == null)
+ try
+ {
+ seType = new CompositeType(StackTraceElement.class.getName(),
+ "An element of a stack trace",
+ new String[] { "className", "methodName",
+ "fileName", "lineNumber",
+ "nativeMethod"
+ },
+ new String[] { "Name of the class",
+ "Name of the method",
+ "Name of the source code file",
+ "Line number",
+ "True if this is a native method"
+ },
+ new OpenType[] {
+ SimpleType.STRING, SimpleType.STRING,
+ SimpleType.STRING, SimpleType.INTEGER,
+ SimpleType.BOOLEAN
+ });
+ }
+ catch (OpenDataException e)
+ {
+ throw new IllegalStateException("Something went wrong in creating " +
+ "the composite data type for the " +
+ "stack trace element.", e);
+ }
+ return seType;
+ }
+
+ /**
* <p>
* Returns a {@link ThreadInfo} instance using the values
* given in the supplied
@@ -336,70 +494,133 @@ public class ThreadInfo
if (data == null)
return null;
CompositeType type = data.getCompositeType();
- checkAttribute(type, "threadId", SimpleType.LONG);
- checkAttribute(type, "threadName", SimpleType.STRING);
- checkAttribute(type, "threadState", SimpleType.STRING);
- checkAttribute(type, "suspended", SimpleType.BOOLEAN);
- checkAttribute(type, "inNative", SimpleType.BOOLEAN);
- checkAttribute(type, "blockedCount", SimpleType.LONG);
- checkAttribute(type, "blockedTime", SimpleType.LONG);
- checkAttribute(type, "waitedCount", SimpleType.LONG);
- checkAttribute(type, "waitedTime", SimpleType.LONG);
- checkAttribute(type, "lockName", SimpleType.STRING);
- checkAttribute(type, "lockOwnerId", SimpleType.LONG);
- checkAttribute(type, "lockOwnerName", SimpleType.STRING);
+ checkAttribute(type, "ThreadId", SimpleType.LONG);
+ checkAttribute(type, "ThreadName", SimpleType.STRING);
+ checkAttribute(type, "ThreadState", SimpleType.STRING);
+ checkAttribute(type, "Suspended", SimpleType.BOOLEAN);
+ checkAttribute(type, "InNative", SimpleType.BOOLEAN);
+ checkAttribute(type, "BlockedCount", SimpleType.LONG);
+ checkAttribute(type, "BlockedTime", SimpleType.LONG);
+ checkAttribute(type, "WaitedCount", SimpleType.LONG);
+ checkAttribute(type, "WaitedTime", SimpleType.LONG);
+ checkAttribute(type, "LockName", SimpleType.STRING);
+ checkAttribute(type, "LockOwnerId", SimpleType.LONG);
+ checkAttribute(type, "LockOwnerName", SimpleType.STRING);
try
{
- CompositeType seType =
- new CompositeType(StackTraceElement.class.getName(),
- "An element of a stack trace",
- new String[] { "className", "methodName",
- "fileName", "lineNumber",
- "nativeMethod"
- },
- new String[] { "Name of the class",
- "Name of the method",
- "Name of the source code file",
- "Line number",
- "True if this is a native method"
- },
- new OpenType[] {
- SimpleType.STRING, SimpleType.STRING,
- SimpleType.STRING, SimpleType.INTEGER,
- SimpleType.BOOLEAN
- });
- checkAttribute(type, "stackTrace", new ArrayType(1, seType));
+ checkAttribute(type, "StackTrace",
+ new ArrayType(1, getStackTraceType()));
+ }
+ catch (OpenDataException e)
+ {
+ throw new IllegalStateException("Something went wrong in creating " +
+ "the array for the stack trace element.",
+ e);
+ }
+ OpenType foundType = type.getType("LockedMonitors");
+ if (foundType != null)
+ try
+ {
+ CompositeType mType = new CompositeType(MonitorInfo.class.getName(),
+ "Information on a object monitor lock",
+ new String[] { "ClassName",
+ "IdentityHashCode",
+ "LockedStackDepth",
+ "LockedStackFrame"
+ },
+ new String[] { "Name of the class",
+ "Identity hash code " +
+ "of the class",
+ "Stack depth at time " +
+ "of lock",
+ "Stack frame at time " +
+ "of lock",
+ },
+ new OpenType[] {
+ SimpleType.STRING, SimpleType.INTEGER,
+ SimpleType.INTEGER, getStackTraceType()
+ });
+ if (!(foundType.equals(new ArrayType(1, mType))))
+ throw new IllegalArgumentException("Field LockedMonitors is not of " +
+ "type " + mType.getClassName());
+ }
+ catch (OpenDataException e)
+ {
+ throw new IllegalStateException("Something went wrong in creating " +
+ "the composite data type for the " +
+ "object monitor information array.", e);
}
+ foundType = type.getType("LockedSynchronizers");
+ if (foundType != null)
+ try
+ {
+ CompositeType lType = new CompositeType(LockInfo.class.getName(),
+ "Information on a lock",
+ new String[] { "ClassName",
+ "IdentityHashCode"
+ },
+ new String[] { "Name of the class",
+ "Identity hash code " +
+ "of the class"
+ },
+ new OpenType[] {
+ SimpleType.STRING, SimpleType.INTEGER
+ });
+ if (!(foundType.equals(new ArrayType(1, lType))))
+ throw new IllegalArgumentException("Field LockedSynchronizers is not of " +
+ "type " + lType.getClassName());
+ }
catch (OpenDataException e)
{
throw new IllegalStateException("Something went wrong in creating " +
"the composite data type for the " +
- "stack trace element.", e);
+ "ownable synchronizerinformation array.", e);
}
- CompositeData[] dTraces = (CompositeData[]) data.get("stackTrace");
+ CompositeData[] dTraces = (CompositeData[]) data.get("StackTrace");
StackTraceElement[] traces = new StackTraceElement[dTraces.length];
for (int a = 0; a < dTraces.length; ++a)
/* FIXME: We can't use the boolean as there is no available
constructor. */
traces[a] =
- new StackTraceElement((String) dTraces[a].get("className"),
- (String) dTraces[a].get("methodName"),
- (String) dTraces[a].get("fileName"),
+ new StackTraceElement((String) dTraces[a].get("ClassName"),
+ (String) dTraces[a].get("MethodName"),
+ (String) dTraces[a].get("FileName"),
((Integer)
- dTraces[a].get("lineNumber")).intValue());
- return new ThreadInfo(((Long) data.get("threadId")).longValue(),
- (String) data.get("threadName"),
- Thread.State.valueOf((String) data.get("threadState")),
- ((Long) data.get("blockedCount")).longValue(),
- ((Long) data.get("blockedTime")).longValue(),
- (String) data.get("lockName"),
- ((Long) data.get("lockOwnerId")).longValue(),
- (String) data.get("lockOwnerName"),
- ((Long) data.get("waitedCount")).longValue(),
- ((Long) data.get("waitedTime")).longValue(),
- ((Boolean) data.get("inNative")).booleanValue(),
- ((Boolean) data.get("suspended")).booleanValue(),
- traces);
+ dTraces[a].get("LineNumber")).intValue());
+ MonitorInfo[] mInfo;
+ if (data.containsKey("LockedMonitors"))
+ {
+ CompositeData[] dmInfos = (CompositeData[]) data.get("LockedMonitors");
+ mInfo = new MonitorInfo[dmInfos.length];
+ for (int a = 0; a < dmInfos.length; ++a)
+ mInfo[a] = MonitorInfo.from(dmInfos[a]);
+ }
+ else
+ mInfo = new MonitorInfo[]{};
+ LockInfo[] lInfo;
+ if (data.containsKey("LockedSynchronizers"))
+ {
+ CompositeData[] dlInfos = (CompositeData[]) data.get("LockedSynchronizers");
+ lInfo = new LockInfo[dlInfos.length];
+ for (int a = 0; a < dlInfos.length; ++a)
+ lInfo[a] = new LockInfo((String) dlInfos[a].get("ClassName"),
+ (Integer) dlInfos[a].get("IdentityHashCode"));
+ }
+ else
+ lInfo = new LockInfo[]{};
+ return new ThreadInfo(((Long) data.get("ThreadId")).longValue(),
+ (String) data.get("ThreadName"),
+ Thread.State.valueOf((String) data.get("ThreadState")),
+ ((Long) data.get("BlockedCount")).longValue(),
+ ((Long) data.get("BlockedTime")).longValue(),
+ (String) data.get("LockName"),
+ ((Long) data.get("LockOwnerId")).longValue(),
+ (String) data.get("LockOwnerName"),
+ ((Long) data.get("WaitedCount")).longValue(),
+ ((Long) data.get("WaitedTime")).longValue(),
+ ((Boolean) data.get("InNative")).booleanValue(),
+ ((Boolean) data.get("Suspended")).booleanValue(),
+ traces, mInfo, lInfo);
}
/**
@@ -459,9 +680,74 @@ public class ThreadInfo
}
/**
+ * Returns an array of {@link MonitorInfo} objects representing
+ * information on the locks on object monitors held by the thread.
+ * If no locks are held, or such information was not requested
+ * on creating this {@link ThreadInfo} object, a zero-length
+ * array will be returned.
+ *
+ * @return information on object monitors locked by this thread.
+ */
+ public MonitorInfo[] getLockedMonitors()
+ {
+ return lockedMonitors;
+ }
+
+ /**
+ * Returns an array of {@link LockInfo} objects representing
+ * information on the locks on ownable synchronizers held by the thread.
+ * If no locks are held, or such information was not requested
+ * on creating this {@link ThreadInfo} object, a zero-length
+ * array will be returned.
+ *
+ * @return information on ownable synchronizers locked by this thread.
+ */
+ public LockInfo[] getLockedSynchronizers()
+ {
+ return lockedSynchronizers;
+ }
+
+ /**
+ * <p>
+ * Returns a {@link LockInfo} object representing the
+ * lock on which this thread is blocked. If the thread
+ * is not blocked, this method returns <code>null</code>.
+ * </p>
+ * <p>
+ * The thread may be blocked due to one of three reasons:
+ * </p>
+ * <ol>
+ * <li>The thread is in the <code>BLOCKED</code> state
+ * waiting to acquire an object monitor in order to enter
+ * a synchronized method or block.</li>
+ * <li>The thread is in the <code>WAITING</code> or
+ * <code>TIMED_WAITING</code> state due to a call to
+ * {@link java.lang.Object#wait()}.</li>
+ * <li>The thread is in the <code>WAITING</code> or
+ * <code>TIMED_WAITING</code> state due to a call
+ * to {@link java.util.concurrent.locks.LockSupport#park()}.
+ * The lock is the return value of
+ * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li>
+ * </ol>
+ *
+ * @return a {@link LockInfo} object representing the lock on
+ * which the thread is blocked, or <code>null</code> if
+ * the thread isn't blocked.
+ * @since 1.6
+ * @see #getLockName()
+ */
+ public LockInfo getLockInfo()
+ {
+ String lockName = getLockName();
+ int at = lockName.indexOf('@');
+ return new LockInfo(lockName.substring(0, at),
+ Integer.decode(lockName.substring(at + 1)));
+ }
+
+ /**
* <p>
* Returns a {@link java.lang.String} representation of
- * the monitor lock on which this thread is blocked. If
+ * the lock on which this thread is blocked. If
* the thread is not blocked, this method returns
* <code>null</code>.
* </p>
@@ -477,7 +763,8 @@ public class ThreadInfo
* and
* <code>Integer.toHexString(System.identityHashCode(l))</code>.
* The value is only unique to the extent that the identity
- * hash code is also unique.
+ * hash code is also unique. The value is the same as would
+ * be returned by <code>getLockInfo().toString()</code>
* </p>
*
* @return a string representing the lock on which this
@@ -486,7 +773,7 @@ public class ThreadInfo
*/
public String getLockName()
{
- if (threadState != Thread.State.BLOCKED)
+ if (!isThreadBlocked())
return null;
return lockName;
}
@@ -504,7 +791,7 @@ public class ThreadInfo
*/
public long getLockOwnerId()
{
- if (threadState != Thread.State.BLOCKED)
+ if (!isThreadBlocked())
return -1;
return lockOwnerId;
}
@@ -522,7 +809,7 @@ public class ThreadInfo
*/
public String getLockOwnerName()
{
- if (threadState != Thread.State.BLOCKED)
+ if (!isThreadBlocked())
return null;
return lockOwnerName;
}
@@ -697,10 +984,40 @@ public class ThreadInfo
", waitedCount=" + waitedCount +
", isInNative=" + isInNative +
", isSuspended=" + isSuspended +
- (threadState == Thread.State.BLOCKED ?
+ (isThreadBlocked() ?
", lockOwnerId=" + lockOwnerId +
", lockOwnerName=" + lockOwnerName : "") +
+ ", lockedMonitors=" + Arrays.toString(lockedMonitors) +
+ ", lockedSynchronizers=" + Arrays.toString(lockedSynchronizers) +
"]";
}
+ /**
+ * <p>
+ * Returns true if the thread is in a blocked state.
+ * The thread is regarded as blocked if:
+ * </p>
+ * <ol>
+ * <li>The thread is in the <code>BLOCKED</code> state
+ * waiting to acquire an object monitor in order to enter
+ * a synchronized method or block.</li>
+ * <li>The thread is in the <code>WAITING</code> or
+ * <code>TIMED_WAITING</code> state due to a call to
+ * {@link java.lang.Object#wait()}.</li>
+ * <li>The thread is in the <code>WAITING</code> or
+ * <code>TIMED_WAITING</code> state due to a call
+ * to {@link java.util.concurrent.locks.LockSupport#park()}.
+ * The lock is the return value of
+ * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li>
+ * </ol>
+ *
+ * @return true if the thread is blocked.
+ */
+ private boolean isThreadBlocked()
+ {
+ return (threadState == Thread.State.BLOCKED ||
+ threadState == Thread.State.WAITING ||
+ threadState == Thread.State.TIMED_WAITING);
+ }
+
}
diff --git a/libjava/classpath/java/lang/management/ThreadMXBean.java b/libjava/classpath/java/lang/management/ThreadMXBean.java
index 669cb3cd8d2..f73075dfdc2 100644
--- a/libjava/classpath/java/lang/management/ThreadMXBean.java
+++ b/libjava/classpath/java/lang/management/ThreadMXBean.java
@@ -57,20 +57,30 @@ package java.lang.management;
* <p>
* This bean supports some optional behaviour, which all
* virtual machines may not choose to implement. Specifically,
- * this includes the monitoring of the CPU time used by a
- * thread, and the monitoring of thread contention. The former
- * is further subdivided into the monitoring of either just
- * the current thread or all threads. The methods
+ * this includes the monitoring of:
+ * </p>
+ * <ul>
+ * <li>the CPU time used by a thread</li>
+ * <li>thread contention</li>
+ * <li>object monitor usage</li>
+ * <li>ownable synchronizer usage</li>
+ * </ul>
+ * <p>
+ * The monitoring of CPU time is further subdivided into
+ * the monitoring of either just the current thread or all
+ * threads. The methods
* {@link #isThreadCpuTimeSupported()},
- * {@link #isCurrentThreadCpuTimeSupported()} and
- * {@link #isThreadContentionMonitoringSupported()} may be
+ * {@link #isCurrentThreadCpuTimeSupported()}
+ * {@link #isThreadContentionMonitoringSupported()},
+ * {@link #isObjectMonitorUsageSupported()} and
+ * {@link #isSynchronizerUsageSupported()} may be
* used to determine whether or not this functionality is
* supported.
* </p>
* <p>
- * Furthermore, both these facilities may be disabled.
- * In fact, thread contention monitoring is disabled by
- * default, and must be explictly turned on by calling
+ * Furthermore, both time and contention monitoring may be
+ * disabled. In fact, thread contention monitoring is disabled
+ * by default, and must be explictly turned on by calling
* the {@link #setThreadContentionMonitoringEnabled(boolean)}
* method.
* </p>
@@ -82,6 +92,70 @@ public interface ThreadMXBean
{
/**
+ * This method returns information on all live threads at the
+ * time of execution (some threads may have terminated by the
+ * time the method completes). This method is simply a shorthand
+ * for calling {@link #getThreadInfo(long[], boolean,
+ * boolean)} with the return value of {@link #getAllThreadIds()}.
+ *
+ * @param lockedMonitors true if the returned {@link ThreadInfo}
+ * objects should contain information on
+ * locked monitors.
+ * @param lockedSynchronizers true if the returned {@link ThreadInfo}
+ * objects should contain information
+ * on locked ownable synchronizers.
+ * @return an array of {@link ThreadInfo} objects for all live threads.
+ * @throws SecurityException if a security manager exists and
+ * denies ManagementPermission("monitor").
+ * @throws UnsupportedOperationException if <code>lockedMonitors</code>
+ * is true, but object monitor
+ * usage monitoring is not supported
+ * by the VM, or
+ * <code>lockedSynchronizers</code>
+ * is true, but ownable synchronizer
+ * usage monitoring is not supported
+ * by the VM.
+ * @since 1.6
+ * @see #getThreadInfo(long[], boolean, boolean)
+ * @see #getAllThreadIds()
+ * @see #isObjectMonitorUsageSupported()
+ * @see #isSynchronizerUsageSupported()
+ */
+ ThreadInfo[] dumpAllThreads(boolean lockedMonitors,
+ boolean lockedSynchronizers);
+
+ /**
+ * <p>
+ * This method obtains a list of threads which are deadlocked
+ * waiting to obtain monitor or ownable synchronizer ownership.
+ * This is similar to the behaviour described for
+ * {@link #getMonitorDeadlockedThreads()}, except this method also
+ * takes in to account deadlocks involving ownable synchronizers.
+ * </p>
+ * <p>
+ * Note that this method is not designed for controlling
+ * synchronization, but for troubleshooting problems which cause such
+ * deadlocks; it may be prohibitively expensive to use in normal
+ * operation. If only deadlocks involving monitors are of interest,
+ * then {@link #findMonitorDeadlockedThreads()} should be used in
+ * preference to this method.
+ * </p>
+ *
+ * @return an array of thread identifiers, corresponding to threads
+ * which are currently in a deadlocked situation, or
+ * <code>null</code> if there are no deadlocks.
+ * @throws SecurityException if a security manager exists and
+ * denies ManagementPermission("monitor").
+ * @throws UnsupportedOperationException if the VM does not support
+ * the monitoring of ownable
+ * synchronizer usage.
+ * @since 1.6
+ * @see #findMonitorDeadlockedThreads()
+ * @see #isSynchronizerUsageSupported()
+ */
+ long[] findDeadlockedThreads();
+
+ /**
* <p>
* This method obtains a list of threads which are deadlocked
* waiting to obtain monitor ownership. On entering a synchronized
@@ -115,13 +189,17 @@ public interface ThreadMXBean
* of A and B. Note that this method is not designed for controlling
* synchronization, but for troubleshooting problems which cause such
* deadlocks; it may be prohibitively expensive to use in normal
- * operation.
+ * operation. This method only returns deadlocks involving monitors;
+ * to include deadlocks involving ownable synchronizers,
+ * {@link #findDeadlockedThreads()} should be used instead.
* </p>
*
* @return an array of thread identifiers, corresponding to threads
- * which are currently in a deadlocked situation.
+ * which are currently in a deadlocked situation, or
+ * <code>null</code> if there are no deadlocks.
* @throws SecurityException if a security manager exists and
* denies ManagementPermission("monitor").
+ * @see #findDeadlockedThreads()
*/
long[] findMonitorDeadlockedThreads();
@@ -285,6 +363,53 @@ public interface ThreadMXBean
ThreadInfo[] getThreadInfo(long[] ids);
/**
+ * Returns information on the specified threads with full
+ * stack trace information and optional synchronization
+ * information. If <code>lockedMonitors</code> is false,
+ * or there are no locked monitors for a particular thread,
+ * then the corresponding {@link ThreadInfo} object will have
+ * an empty {@link MonitorInfo} array. Likewise, if
+ * <code>lockedSynchronizers</code> is false, or there are
+ * no locked ownable synchronizers for a particular thread,
+ * then the corresponding {@link ThreadInfo} object will have
+ * an empty {@link LockInfo} array. If both
+ * <code>lockedMonitors</code> and <code>lockedSynchronizers</code>
+ * are false, the return value is equivalent to that from
+ * <code>{@link #getThreadInfo}(ids, Integer.MAX_VALUE)</code>.
+ * If an identifier specifies a thread which is either non-existant
+ * or not alive, then the corresponding element in the returned
+ * array is <code>null</code>.
+ *
+ * @param ids an array of thread identifiers to return information
+ * on.
+ * @param lockedMonitors true if information on locked monitors
+ * should be included.
+ * @param lockedSynchronizers true if information on locked
+ * ownable synchronizers should be included.
+ * @return an array of {@link ThreadInfo} objects matching the
+ * specified threads. The corresponding element is
+ * <code>null</code> if the identifier specifies
+ * a thread that doesn't exist or is not alive.
+ * @throws IllegalArgumentException if an identifier in the array is
+ * <= 0.
+ * @throws SecurityException if a security manager exists and
+ * denies ManagementPermission("monitor").
+ * @throws UnsupportedOperationException if <code>lockedMonitors</code>
+ * is true, but object monitor
+ * usage monitoring is not supported
+ * by the VM, or
+ * <code>lockedSynchronizers</code>
+ * is true, but ownable synchronizer
+ * usage monitoring is not supported
+ * by the VM.
+ * @since 1.6
+ * @see #isObjectMonitorUsageSupported()
+ * @see #isSynchronizerUsageSupported()
+ */
+ ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors,
+ boolean lockedSynchronizers);
+
+ /**
* Returns information on the specified thread with
* stack trace information to the supplied depth. If the
* identifier specifies a thread which is either non-existant
@@ -390,6 +515,26 @@ public interface ThreadMXBean
boolean isCurrentThreadCpuTimeSupported();
/**
+ * Returns true if the virtual machine supports the monitoring
+ * of object monitor usage.
+ *
+ * @return true if the monitoring of object monitor usage
+ * is supported by the virtual machine.
+ * @since 1.6
+ */
+ boolean isObjectMonitorUsageSupported();
+
+ /**
+ * Returns true if the virtual machine supports the monitoring
+ * of ownable synchronizer usage.
+ *
+ * @return true if the monitoring of ownable synchronizer usage
+ * is supported by the virtual machine.
+ * @since 1.6
+ */
+ boolean isSynchronizerUsageSupported();
+
+ /**
* Returns true if thread contention monitoring is currently
* enabled.
*
diff --git a/libjava/classpath/java/math/BigInteger.java b/libjava/classpath/java/math/BigInteger.java
index c897d8bf48d..8d174d084f2 100644
--- a/libjava/classpath/java/math/BigInteger.java
+++ b/libjava/classpath/java/math/BigInteger.java
@@ -573,7 +573,7 @@ public class BigInteger extends Number implements Comparable<BigInteger>
long y_ext = y.words[i - 1] < 0 ? 0xffffffffL : 0;
for (; i < x.ival; i++)
{
- carry += ((long) x.words[i] & 0xffffffffL) + y_ext;;
+ carry += ((long) x.words[i] & 0xffffffffL) + y_ext;
result.words[i] = (int) carry;
carry >>>= 32;
}
@@ -1912,8 +1912,7 @@ public class BigInteger extends Number implements Comparable<BigInteger>
private static void setBitOp(BigInteger result, int op,
BigInteger x, BigInteger y)
{
- if (y.words == null) ;
- else if (x.words == null || x.ival < y.ival)
+ if ((y.words != null) && (x.words == null || x.ival < y.ival))
{
BigInteger temp = x; x = y; y = temp;
op = swappedOp(op);
diff --git a/libjava/classpath/java/math/class-dependencies.conf b/libjava/classpath/java/math/class-dependencies.conf
deleted file mode 100644
index 4fbf75eb1ce..00000000000
--- a/libjava/classpath/java/math/class-dependencies.conf
+++ /dev/null
@@ -1,58 +0,0 @@
-# This property file contains dependencies of classes, methods, and
-# field on other methods or classes.
-#
-# Syntax:
-#
-# <used>: <needed 1> [... <needed N>]
-#
-# means that when <used> is included, <needed 1> (... <needed N>) must
-# be included as well.
-#
-# <needed X> and <used> are of the form
-#
-# <class.methodOrField(signature)>
-#
-# or just
-#
-# <class>
-#
-# Within dependencies, variables can be used. A variable is defined as
-# follows:
-#
-# {variable}: value1 value2 ... value<n>
-#
-# variables can be used on the right side of dependencies as follows:
-#
-# <used>: com.bla.blu.{variable}.Class.m()V
-#
-# The use of the variable will expand to <n> dependencies of the form
-#
-# <used>: com.bla.blu.value1.Class.m()V
-# <used>: com.bla.blu.value2.Class.m()V
-# ...
-# <used>: com.bla.blu.value<n>.Class.m()V
-#
-# Variables can be redefined when building a system to select the
-# required support for features like encodings, protocols, etc.
-#
-# Hints:
-#
-# - For methods and fields, the signature is mandatory. For
-# specification, please see the Java Virtual Machine Specification by
-# SUN. Unlike in the spec, field signatures (types) are in brackets.
-#
-# - Package names must be separated by '/' (and not '.'). E.g.,
-# java/lang/Class (this is necessary, because the '.' is used to
-# separate method or field names from classes)
-#
-# - In case <needed> refers to a class, only the class itself will be
-# included in the resulting binary, NOT necessarily all its methods
-# and fields. If you want to refer to all methods and fields, you can
-# write class.* as an abbreviation.
-#
-# - Abbreviations for packages are also possible: my/package/* means all
-# methods and fields of all classes in my/package.
-#
-# - A line with a trailing '\' continues in the next line.
-
-# end of file
diff --git a/libjava/classpath/java/net/MimeTypeMapper.java b/libjava/classpath/java/net/MimeTypeMapper.java
index 8153694b483..b0d400cedbf 100644
--- a/libjava/classpath/java/net/MimeTypeMapper.java
+++ b/libjava/classpath/java/net/MimeTypeMapper.java
@@ -232,7 +232,8 @@ class MimeTypeMapper implements FileNameMap
/**
* The MIME types above are put into this Hashtable for faster lookup.
*/
- private Hashtable mime_types = new Hashtable(150);
+ private Hashtable<String, String> mime_types
+ = new Hashtable<String, String>(150);
/**
* Create a new <code>MimeTypeMapper</code> object.
@@ -257,7 +258,7 @@ class MimeTypeMapper implements FileNameMap
}
}
- public static void fillFromFile (Map table, String fname)
+ public static void fillFromFile (Map<String, String> table, String fname)
throws IOException
{
LineNumberReader reader =
@@ -325,17 +326,17 @@ class MimeTypeMapper implements FileNameMap
*/
public static void main(String[] args) throws IOException
{
- TreeMap map = new TreeMap();
+ TreeMap<String, String> map = new TreeMap<String, String>();
// It is fine to hard-code the name here. This is only ever
// used by maintainers, who can hack it if they need to re-run
// it.
fillFromFile(map, "/etc/mime.types");
- Iterator it = map.keySet().iterator();
+ Iterator<String> it = map.keySet().iterator();
boolean first = true;
while (it.hasNext())
{
- String key = (String) it.next();
- String value = (String) map.get(key);
+ String key = it.next();
+ String value = map.get(key);
// Put the "," first since it is easier to make correct syntax this way.
System.out.println(" " + (first ? " " : ", ")
+ "{ \"" + key + "\", \"" + value + "\" }");
diff --git a/libjava/classpath/java/net/MulticastSocket.java b/libjava/classpath/java/net/MulticastSocket.java
index 2841192db61..114d11f2d3c 100644
--- a/libjava/classpath/java/net/MulticastSocket.java
+++ b/libjava/classpath/java/net/MulticastSocket.java
@@ -1,5 +1,5 @@
/* MulticastSocket.java -- Class for using multicast sockets
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -337,7 +337,7 @@ public class MulticastSocket extends DatagramSocket
/**
* Sets the "Time to Live" value for a socket. The value must be between
- * 1 and 255.
+ * 0 and 255, inclusive.
*
* @param ttl The new TTL value
*
@@ -350,7 +350,7 @@ public class MulticastSocket extends DatagramSocket
if (isClosed())
throw new SocketException("socket is closed");
- if (ttl <= 0 || ttl > 255)
+ if (ttl < 0 || ttl > 255)
throw new IllegalArgumentException("Invalid ttl: " + ttl);
getImpl().setTimeToLive(ttl);
diff --git a/libjava/classpath/java/net/NetworkInterface.java b/libjava/classpath/java/net/NetworkInterface.java
index 6c78ead5b4c..a3a6058afa1 100644
--- a/libjava/classpath/java/net/NetworkInterface.java
+++ b/libjava/classpath/java/net/NetworkInterface.java
@@ -40,12 +40,8 @@ package java.net;
import gnu.classpath.SystemProperties;
-import java.util.Collection;
-import java.util.Collections;
import java.util.Enumeration;
-import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map;
import java.util.Vector;
/**
@@ -100,7 +96,8 @@ public final class NetworkInterface
public Enumeration<InetAddress> getInetAddresses()
{
SecurityManager s = System.getSecurityManager();
- Vector inetAddresses = new Vector(netif.addresses);
+ Vector<InetAddress> inetAddresses
+ = new Vector<InetAddress>(netif.addresses);
if (s == null)
return inetAddresses.elements();
diff --git a/libjava/classpath/java/net/Proxy.java b/libjava/classpath/java/net/Proxy.java
index 6f9f1b65be5..315177413ad 100644
--- a/libjava/classpath/java/net/Proxy.java
+++ b/libjava/classpath/java/net/Proxy.java
@@ -57,7 +57,7 @@ public class Proxy
* For compatability with Sun's JDK
*/
private static final long serialVersionUID = -2231209257930100533L;
- };
+ }
public static final Proxy NO_PROXY = new Proxy(Type.DIRECT, null);
diff --git a/libjava/classpath/java/net/ResolverCache.java b/libjava/classpath/java/net/ResolverCache.java
index f8790666a0a..d57df49199c 100644
--- a/libjava/classpath/java/net/ResolverCache.java
+++ b/libjava/classpath/java/net/ResolverCache.java
@@ -97,12 +97,12 @@ class ResolverCache
/**
* The cache itself.
*/
- private static HashMap cache = new HashMap();
+ private static HashMap<Object, Entry> cache = new HashMap<Object, Entry>();
/**
* List of entries which may expire.
*/
- private static LinkedList killqueue = new LinkedList();
+ private static LinkedList<Entry> killqueue = new LinkedList<Entry>();
/**
* Return the hostname for the specified IP address.
diff --git a/libjava/classpath/java/net/ServerSocket.java b/libjava/classpath/java/net/ServerSocket.java
index d5f2a176b81..9cefd29e6b1 100644
--- a/libjava/classpath/java/net/ServerSocket.java
+++ b/libjava/classpath/java/net/ServerSocket.java
@@ -85,9 +85,7 @@ public class ServerSocket
* This constructor is only used by java.nio.
*/
- // FIXME: Workaround a bug in gcj.
- //ServerSocket (PlainSocketImpl impl) throws IOException
- ServerSocket(SocketImpl impl) throws IOException
+ ServerSocket(PlainSocketImpl impl) throws IOException
{
if (impl == null)
throw new NullPointerException("impl may not be null");
@@ -101,8 +99,6 @@ public class ServerSocket
* This method is only used by java.nio.
*/
- // FIXME: Workaround a bug in gcj.
- //PlainSocketImpl getImpl()
SocketImpl getImpl()
{
return impl;
@@ -390,6 +386,7 @@ public class ServerSocket
impl.accept(socket.impl);
socket.bound = true;
+ socket.implCreated = true;
SecurityManager sm = System.getSecurityManager();
if (sm != null)
diff --git a/libjava/classpath/java/net/Socket.java b/libjava/classpath/java/net/Socket.java
index f4f25fe1c1b..64805274241 100644
--- a/libjava/classpath/java/net/Socket.java
+++ b/libjava/classpath/java/net/Socket.java
@@ -1,5 +1,5 @@
/* Socket.java -- Client socket implementation
- Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2006
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2006, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -83,6 +83,12 @@ public class Socket
SocketImpl impl;
/**
+ * True if impl.create() has been called.
+ */
+ // package-private because ServerSocket.implAccept() needs to access it.
+ boolean implCreated;
+
+ /**
* True if the socket is bound.
* Package private so it can be set from ServerSocket when accept is called.
*/
@@ -326,11 +332,23 @@ public class Socket
private SocketImpl getImpl() throws SocketException
{
+ if (! implCreated)
+ {
+ try
+ {
+ impl.create(true);
+ }
+ catch (IOException x)
+ {
+ throw (SocketException) new SocketException().initCause(x);
+ }
+ implCreated = true;
+ }
return impl;
}
/**
- * Binds the socket to the givent local address/port
+ * Binds the socket to the given local address/port
*
* @param bindpoint The address/port to bind to
*
@@ -359,7 +377,6 @@ public class Socket
// bind to address/port
try
{
- getImpl().create(true);
getImpl().bind(tmp.getAddress(), tmp.getPort());
bound = true;
}
diff --git a/libjava/classpath/java/net/URI.java b/libjava/classpath/java/net/URI.java
index 689843c0bf9..43b10fc4195 100644
--- a/libjava/classpath/java/net/URI.java
+++ b/libjava/classpath/java/net/URI.java
@@ -693,7 +693,7 @@ public final class URI
String portStr = getURIGroup(matcher, AUTHORITY_PORT_GROUP);
- if (portStr != null)
+ if (portStr != null && ! portStr.isEmpty())
try
{
port = Integer.parseInt(portStr);
diff --git a/libjava/classpath/java/net/URL.java b/libjava/classpath/java/net/URL.java
index 8f72d0687e4..16a606fbc7e 100644
--- a/libjava/classpath/java/net/URL.java
+++ b/libjava/classpath/java/net/URL.java
@@ -190,7 +190,8 @@ public final class URL implements Serializable
* This a table where we cache protocol handlers to avoid the overhead
* of looking them up each time.
*/
- private static HashMap ph_cache = new HashMap();
+ private static HashMap<String, URLStreamHandler> ph_cache
+ = new HashMap<String, URLStreamHandler>();
/**
* Whether or not to cache protocol handlers.
@@ -901,7 +902,7 @@ public final class URL implements Serializable
// First, see if a protocol handler is in our cache.
if (cache_handlers)
{
- if ((ph = (URLStreamHandler) ph_cache.get(protocol)) != null)
+ if ((ph = ph_cache.get(protocol)) != null)
return ph;
}
@@ -934,9 +935,9 @@ public final class URL implements Serializable
// Cache the systemClassLoader
if (systemClassLoader == null)
{
- systemClassLoader = (ClassLoader) AccessController.doPrivileged
- (new PrivilegedAction() {
- public Object run()
+ systemClassLoader = AccessController.doPrivileged
+ (new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run()
{
return ClassLoader.getSystemClassLoader();
}
diff --git a/libjava/classpath/java/net/URLClassLoader.java b/libjava/classpath/java/net/URLClassLoader.java
index 7e2353ac27e..6df2818c5c9 100644
--- a/libjava/classpath/java/net/URLClassLoader.java
+++ b/libjava/classpath/java/net/URLClassLoader.java
@@ -145,7 +145,7 @@ public class URLClassLoader extends SecureClassLoader
// Instance variables
/** Locations to load classes from */
- private final Vector urls = new Vector();
+ private final Vector<URL> urls = new Vector<URL>();
/**
* Store pre-parsed information for each url into this vector: each
@@ -153,7 +153,7 @@ public class URLClassLoader extends SecureClassLoader
* attribute which adds to the URLs that will be searched, but this
* does not add to the list of urls.
*/
- private final Vector urlinfos = new Vector();
+ private final Vector<URLLoader> urlinfos = new Vector<URLLoader>();
/** Factory used to get the protocol handlers of the URLs */
private final URLStreamHandlerFactory factory;
@@ -301,7 +301,6 @@ public class URLClassLoader extends SecureClassLoader
if ("file".equals (protocol))
{
File dir = new File(file);
- URL absUrl;
try
{
absoluteURL = dir.getCanonicalFile().toURL();
@@ -329,12 +328,12 @@ public class URLClassLoader extends SecureClassLoader
// First see if we can find a handler with the correct name.
try
{
- Class handler = Class.forName(URL_LOADER_PREFIX + protocol);
- Class[] argTypes = new Class[] { URLClassLoader.class,
- URLStreamHandlerCache.class,
- URLStreamHandlerFactory.class,
- URL.class,
- URL.class };
+ Class<?> handler = Class.forName(URL_LOADER_PREFIX + protocol);
+ Class<?>[] argTypes = new Class<?>[] { URLClassLoader.class,
+ URLStreamHandlerCache.class,
+ URLStreamHandlerFactory.class,
+ URL.class,
+ URL.class };
Constructor k = handler.getDeclaredConstructor(argTypes);
loader
= (URLLoader) k.newInstance(new Object[] { this,
@@ -395,7 +394,7 @@ public class URLClassLoader extends SecureClassLoader
}
urlinfos.add(loader);
- ArrayList extra = loader.getClassPath();
+ ArrayList<URLLoader> extra = loader.getClassPath();
if (extra != null)
urlinfos.addAll(extra);
}
@@ -602,10 +601,10 @@ public class URLClassLoader extends SecureClassLoader
Class result = null;
if (sm != null && securityContext != null)
{
- result = (Class)AccessController.doPrivileged
- (new PrivilegedAction()
+ result = AccessController.doPrivileged
+ (new PrivilegedAction<Class>()
{
- public Object run()
+ public Class run()
{
return defineClass(className, classData,
0, classData.length,
@@ -848,9 +847,9 @@ public class URLClassLoader extends SecureClassLoader
+ securityContext);
URLClassLoader loader =
- (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction()
+ AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>()
{
- public Object run()
+ public URLClassLoader run()
{
return new URLClassLoader(parent,
(AccessControlContext) securityContext);
diff --git a/libjava/classpath/java/net/class-dependencies.conf b/libjava/classpath/java/net/class-dependencies.conf
deleted file mode 100644
index 8b130f53684..00000000000
--- a/libjava/classpath/java/net/class-dependencies.conf
+++ /dev/null
@@ -1,122 +0,0 @@
-# This property file contains dependencies of classes, methods, and
-# field on other methods or classes.
-#
-# Syntax:
-#
-# <used>: <needed 1> [... <needed N>]
-#
-# means that when <used> is included, <needed 1> (... <needed N>) must
-# be included as well.
-#
-# <needed X> and <used> are of the form
-#
-# <class.methodOrField(signature)>
-#
-# or just
-#
-# <class>
-#
-# Within dependencies, variables can be used. A variable is defined as
-# follows:
-#
-# {variable}: value1 value2 ... value<n>
-#
-# variables can be used on the right side of dependencies as follows:
-#
-# <used>: com.bla.blu.{variable}.Class.m()V
-#
-# The use of the variable will expand to <n> dependencies of the form
-#
-# <used>: com.bla.blu.value1.Class.m()V
-# <used>: com.bla.blu.value2.Class.m()V
-# ...
-# <used>: com.bla.blu.value<n>.Class.m()V
-#
-# Variables can be redefined when building a system to select the
-# required support for features like encodings, protocols, etc.
-#
-# Hints:
-#
-# - For methods and fields, the signature is mandatory. For
-# specification, please see the Java Virtual Machine Specification by
-# SUN. Unlike in the spec, field signatures (types) are in brackets.
-#
-# - Package names must be separated by '/' (and not '.'). E.g.,
-# java/lang/Class (this is necessary, because the '.' is used to
-# separate method or field names from classes)
-#
-# - In case <needed> refers to a class, only the class itself will be
-# included in the resulting binary, NOT necessarily all its methods
-# and fields. If you want to refer to all methods and fields, you can
-# write class.* as an abbreviation.
-#
-# - Abbreviations for packages are also possible: my/package/* means all
-# methods and fields of all classes in my/package.
-#
-# - A line with a trailing '\' continues in the next line.
-
-java/net/InetAddress: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/net/UnknownHostException.<init>(Ljava/lang/String;)V
-
-java/net/DatagramSocketImpl: \
- java/net/DatagramSocketImpl.fd(Ljava/io/FileDescriptor;) \
- java/net/DatagramSocketImpl.localPort(I)
-
-java/net/PlainDatagramSocketImpl: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/io/IOException.<init>(Ljava/lang/String;)V \
- java/io/FileDescriptor.<init>()V \
- java/lang/Boolean.<init>(Z)V \
- java/lang/Integer.<init>(I)V \
- java/net/InetAddress.getByName(Ljava/lang/String;)Ljava/net/InetAddress; \
- java/net/InetAddress.getAddress()[B \
- java/lang/Boolean.booleanValue()Z \
- java/lang/Integer.intValue()I \
- java/net/SocketException.<init>(Ljava/lang/String;)V \
- java/net/DatagramPacket.getData()[B \
- java/net/SocketImpl.address(Ljava/net/InetAddress;) \
- java/net/PlainSocketImpl.native_fd(I) \
- java/net/SocketImpl.fd(Ljava/io/FileDescriptor;) \
- java/net/SocketImpl.address(Ljava/net/InetAddress;) \
- java/net/PlainDatagramSocketImpl.native_fd(I) \
- java/net/SocketImpl.localport(I) \
- java/net/SocketImpl.port(I)
-
-java/net/PlainSocketImpl: \
- java/lang/ClassNotFoundException.<init>(Ljava/lang/String;)V \
- java/lang/InternalError.<init>(Ljava/lang/String;)V \
- java/io/IOException.<init>(Ljava/lang/String;)V \
- java/io/FileDescriptor.<init>()V \
- java/lang/Boolean.<init>(Z)V \
- java/lang/Integer.<init>(I)V \
- java/net/InetAddress.getByName(Ljava/lang/String;)Ljava/net/InetAddress; \
- java/net/InetAddress.getAddress()[B \
- java/lang/Boolean.booleanValue()Z \
- java/lang/Integer.intValue()I \
- java/net/SocketException.<init>(Ljava/lang/String;)V \
- java/net/DatagramPacket.getData()[B \
- java/net/SocketImpl.address(Ljava/net/InetAddress;) \
- java/net/PlainSocketImpl.native_fd(I) \
- java/net/SocketImpl.fd(Ljava/io/FileDescriptor;) \
- java/net/SocketImpl.address(Ljava/net/InetAddress;) \
- java/net/PlainDatagramSocketImpl.native_fd(I) \
- java/net/SocketImpl.localport(I) \
- java/net/SocketImpl.port(I)
-
-# All protocols supported are loaded via URL.getURLStreamHandler from
-# class gnu.java.net.protocol.<protocol>.Handler.
-#
-# This introduces a dependency for all protocols. To allow an easy selection
-# and addition of protocols, the library variable {protocols} can be set to
-# the set of supported protocols.
-#
-{protocols}: http file jar
-
-java/net/URL.getURLStreamHandler(Ljava/lang/String;)Ljava/net/URLStreamHandler;: \
- gnu/java/net/protocol/{protocols}/Handler.* \
- com/aicas/java/net/protocol/rom/Handler.*
-
-# end of file
diff --git a/libjava/classpath/java/nio/ByteOrder.java b/libjava/classpath/java/nio/ByteOrder.java
index 39a3ff893bd..0e3b9173eb6 100644
--- a/libjava/classpath/java/nio/ByteOrder.java
+++ b/libjava/classpath/java/nio/ByteOrder.java
@@ -61,7 +61,9 @@ public final class ByteOrder
*/
public static ByteOrder nativeOrder()
{
- return (System.getProperty ("gnu.cpu.endian").equals("big")
+ // Let this fail with an NPE when the property is not set correctly.
+ // Otherwise we risk that NIO is silently working wrong.
+ return (System.getProperty("gnu.cpu.endian").equals("big")
? BIG_ENDIAN : LITTLE_ENDIAN);
}
diff --git a/libjava/classpath/java/nio/channels/spi/SelectorProvider.java b/libjava/classpath/java/nio/channels/spi/SelectorProvider.java
index db4e65fe14e..b2fb7bb9c81 100644
--- a/libjava/classpath/java/nio/channels/spi/SelectorProvider.java
+++ b/libjava/classpath/java/nio/channels/spi/SelectorProvider.java
@@ -40,6 +40,7 @@ package java.nio.channels.spi;
import gnu.java.nio.SelectorProviderImpl;
import java.io.IOException;
+import java.nio.channels.Channel;
import java.nio.channels.DatagramChannel;
import java.nio.channels.Pipe;
import java.nio.channels.ServerSocketChannel;
@@ -115,6 +116,32 @@ public abstract class SelectorProvider
public abstract SocketChannel openSocketChannel() throws IOException;
/**
+ * Returns the inherited channel of the VM.
+ *
+ * @return the inherited channel of the VM
+ *
+ * @throws IOException If an I/O error occurs
+ * @throws SecurityException If an installed security manager denies access
+ * to RuntimePermission("inheritedChannel")
+ *
+ * @since 1.5
+ */
+ public Channel inheritedChannel()
+ throws IOException
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ sm.checkPermission(new RuntimePermission("inheritedChannel"));
+ }
+ // Implementation note: The default implementation can't do much more
+ // than return null. If a VM can provide something more useful it should
+ // install its own SelectorProvider (maybe a subclass of this one) to
+ // return something more useful.
+ return null;
+ }
+
+ /**
* Returns the system-wide default selector provider for this invocation
* of the Java virtual machine.
*
diff --git a/libjava/classpath/java/nio/class-dependencies.conf b/libjava/classpath/java/nio/class-dependencies.conf
deleted file mode 100644
index 4fbf75eb1ce..00000000000
--- a/libjava/classpath/java/nio/class-dependencies.conf
+++ /dev/null
@@ -1,58 +0,0 @@
-# This property file contains dependencies of classes, methods, and
-# field on other methods or classes.
-#
-# Syntax:
-#
-# <used>: <needed 1> [... <needed N>]
-#
-# means that when <used> is included, <needed 1> (... <needed N>) must
-# be included as well.
-#
-# <needed X> and <used> are of the form
-#
-# <class.methodOrField(signature)>
-#
-# or just
-#
-# <class>
-#
-# Within dependencies, variables can be used. A variable is defined as
-# follows:
-#
-# {variable}: value1 value2 ... value<n>
-#
-# variables can be used on the right side of dependencies as follows:
-#
-# <used>: com.bla.blu.{variable}.Class.m()V
-#
-# The use of the variable will expand to <n> dependencies of the form
-#
-# <used>: com.bla.blu.value1.Class.m()V
-# <used>: com.bla.blu.value2.Class.m()V
-# ...
-# <used>: com.bla.blu.value<n>.Class.m()V
-#
-# Variables can be redefined when building a system to select the
-# required support for features like encodings, protocols, etc.
-#
-# Hints:
-#
-# - For methods and fields, the signature is mandatory. For
-# specification, please see the Java Virtual Machine Specification by
-# SUN. Unlike in the spec, field signatures (types) are in brackets.
-#
-# - Package names must be separated by '/' (and not '.'). E.g.,
-# java/lang/Class (this is necessary, because the '.' is used to
-# separate method or field names from classes)
-#
-# - In case <needed> refers to a class, only the class itself will be
-# included in the resulting binary, NOT necessarily all its methods
-# and fields. If you want to refer to all methods and fields, you can
-# write class.* as an abbreviation.
-#
-# - Abbreviations for packages are also possible: my/package/* means all
-# methods and fields of all classes in my/package.
-#
-# - A line with a trailing '\' continues in the next line.
-
-# end of file
diff --git a/libjava/classpath/java/rmi/activation/ActivationID.java b/libjava/classpath/java/rmi/activation/ActivationID.java
index c4bbcd285c5..e1cc8a712e1 100644
--- a/libjava/classpath/java/rmi/activation/ActivationID.java
+++ b/libjava/classpath/java/rmi/activation/ActivationID.java
@@ -174,7 +174,7 @@ public class ActivationID
{
out.writeObject(uid);
out.writeObject(activator);
- };
+ }
/**
* Compare by .equals if both a and b are not null, compare directly if at
diff --git a/libjava/classpath/java/rmi/server/UnicastRemoteObject.java b/libjava/classpath/java/rmi/server/UnicastRemoteObject.java
index 31bf8802301..6ef3432b567 100644
--- a/libjava/classpath/java/rmi/server/UnicastRemoteObject.java
+++ b/libjava/classpath/java/rmi/server/UnicastRemoteObject.java
@@ -239,11 +239,12 @@ public class UnicastRemoteObject extends RemoteServer
(UnicastServerRef) ((RemoteObject) obj).getRef();
return sref.unexportObject(obj, force);
}
- else
+ // FIXME
+ /* else
{
- // FIXME
;
}
+ */
return true;
}
diff --git a/libjava/classpath/java/security/BasicPermission.java b/libjava/classpath/java/security/BasicPermission.java
index ef2cc4df094..6296cffea36 100644
--- a/libjava/classpath/java/security/BasicPermission.java
+++ b/libjava/classpath/java/security/BasicPermission.java
@@ -73,9 +73,8 @@ import java.util.Hashtable;
* @since 1.1
* @status updated to 1.4
*/
-public abstract class BasicPermission extends java.security.Permission
+public abstract class BasicPermission extends Permission
implements Serializable
- // FIXME extends with fully qualified classname as workaround for gcj 3.3.
{
/**
* Compatible with JDK 1.1+.
diff --git a/libjava/classpath/java/security/Permission.java b/libjava/classpath/java/security/Permission.java
index 48f4d52a18c..9072d95652e 100644
--- a/libjava/classpath/java/security/Permission.java
+++ b/libjava/classpath/java/security/Permission.java
@@ -181,7 +181,20 @@ public abstract class Permission implements Guard, Serializable
*/
public String toString()
{
- return '(' + getClass().getName() + ' ' + getName() + ' '
- + getActions() + ')';
+ StringBuffer string = new StringBuffer();
+
+ string = string.append('(');
+ string = string.append(getClass().getName());
+ string = string.append(' ');
+ string = string.append(getName());
+
+ if (!(getActions().equals("")))
+ {
+ string = string.append(' ');
+ string = string.append(getActions());
+ }
+
+ string = string.append(')');
+ return string.toString();
}
} // class Permission
diff --git a/libjava/classpath/java/security/SecureClassLoader.java b/libjava/classpath/java/security/SecureClassLoader.java
index dfc1758b52f..f683f9a700f 100644
--- a/libjava/classpath/java/security/SecureClassLoader.java
+++ b/libjava/classpath/java/security/SecureClassLoader.java
@@ -99,7 +99,7 @@ public class SecureClassLoader extends ClassLoader
*
* @since 1.5
*/
- protected final Class defineClass(String name, ByteBuffer b, CodeSource cs)
+ protected final Class<?> defineClass(String name, ByteBuffer b, CodeSource cs)
{
return super.defineClass(name, b, getProtectionDomain(cs));
}
diff --git a/libjava/classpath/java/security/SignatureSpi.java b/libjava/classpath/java/security/SignatureSpi.java
index 3b46815eca9..80ecbfd44e0 100644
--- a/libjava/classpath/java/security/SignatureSpi.java
+++ b/libjava/classpath/java/security/SignatureSpi.java
@@ -136,16 +136,23 @@ public abstract class SignatureSpi
* bytes of the given buffer.
*
* @param input The input buffer.
- * @throws SignatureException
+ * @throws IllegalStateException if the engine is not properly initialized.
*/
- protected void engineUpdate(ByteBuffer input) throws SignatureException
+ protected void engineUpdate(ByteBuffer input)
{
byte[] buf = new byte[4096];
while (input.hasRemaining())
{
int l = Math.min(input.remaining(), buf.length);
input.get(buf, 0, l);
- engineUpdate(buf, 0, l);
+ try
+ {
+ engineUpdate(buf, 0, l);
+ }
+ catch (SignatureException se)
+ {
+ throw new IllegalStateException(se);
+ }
}
}
diff --git a/libjava/classpath/java/security/cert/X509CertSelector.java b/libjava/classpath/java/security/cert/X509CertSelector.java
index 154ed2e4d98..7a7db086b0a 100644
--- a/libjava/classpath/java/security/cert/X509CertSelector.java
+++ b/libjava/classpath/java/security/cert/X509CertSelector.java
@@ -1,5 +1,5 @@
/* X509CertSelector.java -- selects X.509 certificates by criteria.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,9 +40,17 @@ package java.security.cert;
import gnu.classpath.SystemProperties;
import gnu.java.security.OID;
+import gnu.java.security.x509.GnuPKIExtension;
+import gnu.java.security.x509.ext.CertificatePolicies;
+import gnu.java.security.x509.ext.Extension;
+import gnu.java.security.x509.ext.GeneralName;
+import gnu.java.security.x509.ext.GeneralSubtree;
+import gnu.java.security.x509.ext.NameConstraints;
+import gnu.java.security.x509.ext.GeneralName.Kind;
import java.io.IOException;
import java.math.BigInteger;
+import java.net.InetAddress;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
@@ -88,6 +96,48 @@ public class X509CertSelector implements CertSelector, Cloneable
private static final String SUBJECT_KEY_ID = "2.5.29.14";
private static final String NAME_CONSTRAINTS_ID = "2.5.29.30";
+ private static boolean checkOid(int[] oid)
+ {
+ return (oid != null && oid.length > 2 &&
+ (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39));
+ }
+
+ private static GeneralName makeName(int id, String name) throws IOException
+ {
+ byte[] nameBytes = null;
+ GeneralName.Kind kind = GeneralName.Kind.forTag(id);
+ switch (Kind.forTag(id))
+ {
+ case dNSName:
+ case rfc822Name:
+ case uniformResourceIdentifier:
+ nameBytes = name.getBytes("ASCII");
+ break;
+
+ case iPAddress:
+ InetAddress addr = InetAddress.getByName(name);
+ nameBytes = addr.getAddress();
+ break;
+
+ case registeredId:
+ OID oid = new OID(name);
+ nameBytes = oid.getDER();
+ break;
+
+ case directoryName:
+ X500Principal xname = new X500Principal(name);
+ nameBytes = xname.getEncoded();
+ break;
+
+ case ediPartyName:
+ case x400Address:
+ case otherName:
+ throw new IOException("cannot decode string representation of "
+ + kind);
+ }
+ return new GeneralName(kind, nameBytes);
+ }
+
private int basicConstraints;
private X509Certificate cert;
private BigInteger serialNo;
@@ -100,14 +150,12 @@ public class X509CertSelector implements CertSelector, Cloneable
private OID sigId;
private PublicKey subjectKey;
private X509EncodedKeySpec subjectKeySpec;
- private Set keyPurposeSet;
- private List altNames;
+ private Set<String> keyPurposeSet;
+ private List<GeneralName> altNames;
private boolean matchAllNames;
private byte[] nameConstraints;
- private Set policy;
-
- // Constructors.
- // ------------------------------------------------------------------------
+ private Set<OID> policy;
+ private List<GeneralName> pathToNames;
/**
* Creates a new X.509 certificate selector. The new selector will be
@@ -119,285 +167,280 @@ public class X509CertSelector implements CertSelector, Cloneable
basicConstraints = -1;
}
- // Instance methods.
- // ------------------------------------------------------------------------
-
/**
- * Returns the certificate criterion, or <code>null</code> if this value
- * was not set.
+ * Add a name to match in the NameConstraints extension. The argument is
+ * the DER-encoded bytes of a GeneralName structure.
+ *
+ * See the method {@link #addSubjectAlternativeName(int, byte[])} for the
+ * format of the GeneralName structure.
*
- * @return The certificate.
+ * @param id The name identifier. Must be between 0 and 8.
+ * @param name The DER-encoded bytes of the name to match.
+ * @throws IOException If the name DER is malformed.
*/
- public X509Certificate getCertificate()
+ public void addPathToName(int id, byte[] name) throws IOException
{
- return cert;
+ GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name);
+ if (pathToNames == null)
+ pathToNames = new LinkedList<GeneralName>();
+ pathToNames.add(generalName);
}
/**
- * Sets the certificate criterion. If set, only certificates that are
- * equal to the certificate passed here will be accepted.
+ * Add a name to match in the NameConstraints extension. This method will
+ * only recognize certain types of name that have convenient string
+ * encodings. For robustness, you should use the {@link
+ * #addPathToName(int, byte[])} method whenever possible.
*
- * @param cert The certificate.
+ * @param id The name identifier. Must be between 0 and 8.
+ * @param name The name.
+ * @throws IOException If the name cannot be decoded.
*/
- public void setCertificate(X509Certificate cert)
+ public void addPathToName(int id, String name) throws IOException
{
- this.cert = cert;
+ GeneralName generalName = makeName(id, name);
+ if (pathToNames == null)
+ pathToNames = new LinkedList<GeneralName>();
+ pathToNames.add(generalName);
}
/**
- * Returns the serial number criterion, or <code>null</code> if this
- * value was not set.
+ * Add a name, as DER-encoded bytes, to the subject alternative names
+ * criterion.
+ *
+ * The name is a GeneralName structure, which has the ASN.1 format:
+ *
+ * <pre>
+ GeneralName ::= CHOICE {
+ otherName [0] OtherName,
+ rfc822Name [1] IA5String,
+ dNSName [2] IA5String,
+ x400Address [3] ORAddress,
+ directoryName [4] Name,
+ ediPartyName [5] EDIPartyName,
+ uniformResourceIdentifier [6] IA5String,
+ iPAddress [7] OCTET STRING,
+ registeredID [8] OBJECT IDENTIFIER }
+</pre>
*
- * @return The serial number.
+ * @param id The type of name this is.
+ * @param name The DER-encoded name.
+ * @throws IOException If the name is not a valid DER sequence.
*/
- public BigInteger getSerialNumber()
+ public void addSubjectAlternativeName(int id, byte[] name)
+ throws IOException
{
- return serialNo;
+ GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name);
+ if (altNames == null)
+ altNames = new LinkedList<GeneralName>();
+ altNames.add(generalName);
}
/**
- * Sets the serial number of the desired certificate. Only certificates that
- * contain this serial number are accepted.
+ * Add a name to the subject alternative names criterion. This method will
+ * only recognize certain types of name that have convenient string
+ * encodings. For robustness, you should use the {@link
+ * #addSubjectAlternativeName(int, byte[])} method whenever possible.
+ *
+ * This method can only decode certain name kinds of names as strings.
*
- * @param serialNo The serial number.
+ * @param id The type of name this is. Must be in the range [0,8].
+ * @param name The name.
+ * @throws IOException If the id is out of range, or if the name
+ * is null.
*/
- public void setSerialNumber(BigInteger serialNo)
+ public void addSubjectAlternativeName(int id, String name)
+ throws IOException
{
- this.serialNo = serialNo;
+ GeneralName generalName = makeName(id, name);
+ if (altNames == null)
+ altNames = new LinkedList<GeneralName>();
+ altNames.add(generalName);
}
- /**
- * Returns the issuer criterion as a string, or <code>null</code> if this
- * value was not set.
- *
- * @return The issuer.
- */
- public String getIssuerAsString()
+ public Object clone()
{
- if (issuer != null)
- return issuer.getName();
- else
- return null;
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException shouldNotHappen)
+ {
+ throw new Error(shouldNotHappen);
+ }
}
/**
- * Returns the issuer criterion as a sequence of DER bytes, or
- * <code>null</code> if this value was not set.
+ * Returns the authority key identifier criterion, or <code>null</code> if
+ * this value was not set. Note that the byte array is cloned to prevent
+ * modification.
*
- * @return The issuer.
+ * @return The authority key identifier.
*/
- public byte[] getIssuerAsBytes() throws IOException
+ public byte[] getAuthorityKeyIdentifier()
{
- if (issuer != null)
- return issuer.getEncoded();
+ if (authKeyId != null)
+ return (byte[]) authKeyId.clone();
else
return null;
}
/**
- * Sets the issuer, specified as a string representation of the issuer's
- * distinguished name. Only certificates issued by this issuer will
- * be accepted.
+ * Returns the basic constraints criterion, or -1 if this value is not set.
*
- * @param name The string representation of the issuer's distinguished name.
- * @throws IOException If the given name is incorrectly formatted.
+ * @return The basic constraints.
*/
- public void setIssuer(String name) throws IOException
+ public int getBasicConstraints()
{
- if (name != null)
- {
- try
- {
- issuer = new X500Principal(name);
- }
- catch (IllegalArgumentException iae)
- {
- throw new IOException(iae.getMessage());
- }
- }
- else
- issuer = null;
+ return basicConstraints;
}
/**
- * Sets the issuer, specified as the DER encoding of the issuer's
- * distinguished name. Only certificates issued by this issuer will
- * be accepted.
+ * Returns the certificate criterion, or <code>null</code> if this value
+ * was not set.
*
- * @param name The DER encoding of the issuer's distinguished name.
- * @throws IOException If the given name is incorrectly formatted.
+ * @return The certificate.
*/
- public void setIssuer(byte[] name) throws IOException
+ public X509Certificate getCertificate()
{
- if (name != null)
- {
- try
- {
- issuer = new X500Principal(name);
- }
- catch (IllegalArgumentException iae)
- {
- throw new IOException(iae.getMessage());
- }
- }
- else
- issuer = null;
+ return cert;
}
/**
- * Returns the subject criterion as a string, of <code>null</code> if
- * this value was not set.
+ * Returns the date at which certificates must be valid, or <code>null</code>
+ * if this criterion was not set.
*
- * @return The subject.
+ * @return The target certificate valitity date.
*/
- public String getSubjectAsString()
+ public Date getCertificateValid()
{
- if (subject != null)
- return subject.getName();
+ if (certValid != null)
+ return (Date) certValid.clone();
else
return null;
}
/**
- * Returns the subject criterion as a sequence of DER bytes, or
- * <code>null</code> if this value is not set.
+ * Returns the set of extended key purpose IDs, as an unmodifiable set
+ * of OID strings. Returns <code>null</code> if this criterion is not
+ * set.
*
- * @return The subject.
+ * @return The set of key purpose OIDs (strings).
*/
- public byte[] getSubjectAsBytes() throws IOException
+ public Set<String> getExtendedKeyUsage()
{
- if (subject != null)
- return subject.getEncoded();
+ if (keyPurposeSet != null)
+ return Collections.unmodifiableSet(keyPurposeSet);
else
return null;
}
/**
- * Sets the subject, specified as a string representation of the
- * subject's distinguished name. Only certificates with the given
- * subject will be accepted.
+ * Returns the issuer criterion as a sequence of DER bytes, or
+ * <code>null</code> if this value was not set.
*
- * @param name The string representation of the subject's distinguished name.
- * @throws IOException If the given name is incorrectly formatted.
+ * @return The issuer.
*/
- public void setSubject(String name) throws IOException
+ public byte[] getIssuerAsBytes() throws IOException
{
- if (name != null)
- {
- try
- {
- subject = new X500Principal(name);
- }
- catch (IllegalArgumentException iae)
- {
- throw new IOException(iae.getMessage());
- }
- }
+ if (issuer != null)
+ return issuer.getEncoded();
else
- subject = null;
+ return null;
}
/**
- * Sets the subject, specified as the DER encoding of the subject's
- * distinguished name. Only certificates with the given subject will
- * be accepted.
+ * Returns the issuer criterion as a string, or <code>null</code> if this
+ * value was not set.
*
- * @param name The DER encoding of the subject's distinguished name.
- * @throws IOException If the given name is incorrectly formatted.
+ * @return The issuer.
*/
- public void setSubject(byte[] name) throws IOException
+ public String getIssuerAsString()
{
- if (name != null)
- {
- try
- {
- subject = new X500Principal(name);
- }
- catch (IllegalArgumentException iae)
- {
- throw new IOException(iae.getMessage());
- }
- }
+ if (issuer != null)
+ return issuer.getName();
else
- subject = null;
+ return null;
}
/**
- * Returns the subject key identifier criterion, or <code>null</code> if
- * this value was not set. Note that the byte array is cloned to prevent
- * modification.
+ * Returns the public key usage criterion, or <code>null</code> if this
+ * value is not set. Note that the array is cloned to prevent modification.
*
- * @return The subject key identifier.
+ * @return The public key usage.
*/
- public byte[] getSubjectKeyIdentifier()
+ public boolean[] getKeyUsage()
{
- if (subjectKeyId != null)
- return (byte[]) subjectKeyId.clone();
+ if (keyUsage != null)
+ return (boolean[]) keyUsage.clone();
else
return null;
}
/**
- * Sets the subject key identifier criterion, or <code>null</code> to clear
- * this criterion. Note that the byte array is cloned to prevent modification.
+ * Returns whether or not all specified alternative names must match.
+ * If false, a certificate is considered a match if <em>one</em> of the
+ * specified alternative names matches.
*
- * @param subjectKeyId The subject key identifier.
+ * @return true if all names must match.
*/
- public void setSubjectKeyIdentifier(byte[] subjectKeyId)
+ public boolean getMatchAllSubjectAltNames()
{
- this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() :
- null;
+ return matchAllNames;
}
/**
- * Returns the authority key identifier criterion, or <code>null</code> if
- * this value was not set. Note that the byte array is cloned to prevent
+ * Returns the name constraints criterion, or <code>null</code> if this
+ * value is not set. Note that the byte array is cloned to prevent
* modification.
*
- * @return The authority key identifier.
+ * @return The name constraints.
*/
- public byte[] getAuthorityKeyIdentifier()
+ public byte[] getNameConstraints()
{
- if (authKeyId != null)
- return (byte[]) authKeyId.clone();
+ if (nameConstraints != null)
+ return (byte[]) nameConstraints.clone();
else
return null;
}
- /**
- * Sets the authority key identifier criterion, or <code>null</code> to clear
- * this criterion. Note that the byte array is cloned to prevent modification.
- *
- * @param authKeyId The authority key identifier.
- */
- public void setAuthorityKeyIdentifier(byte[] authKeyId)
+ public Collection<List<?>> getPathToNames()
{
- this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null;
- }
-
- /**
- * Returns the date at which certificates must be valid, or <code>null</code>
- * if this criterion was not set.
- *
- * @return The target certificate valitity date.
- */
- public Date getCertificateValid()
- {
- if (certValid != null)
- return (Date) certValid.clone();
- else
- return null;
+ if (pathToNames != null)
+ {
+ List<List<?>> names = new ArrayList<List<?>>(pathToNames.size());
+ for (GeneralName name : pathToNames)
+ {
+ List<Object> n = new ArrayList<Object>(2);
+ n.add(name.kind().tag());
+ n.add(name.name());
+ names.add(n);
+ }
+
+ return names;
+ }
+ return null;
}
/**
- * Sets the date at which certificates must be valid. Specify
- * <code>null</code> to clear this criterion.
+ * Returns the certificate policy extension that will be matched by this
+ * selector, or null if the certificate policy will not be matched.
*
- * @param certValid The certificate validity date.
+ * @return The policy to be matched, or null.
*/
- public void setCertificateValid(Date certValid)
+ public Set<String> getPolicy()
{
- this.certValid = certValid != null ? (Date) certValid.clone() : null;
+ Set<OID> p = this.policy;
+ if (p != null)
+ {
+ Set<String> strings = new HashSet<String>(p.size());
+ for (OID o : p)
+ {
+ strings.add(o.toString());
+ }
+ return strings;
+ }
+ return null;
}
/**
@@ -418,59 +461,83 @@ public class X509CertSelector implements CertSelector, Cloneable
}
/**
- * This method, and its related X.509 certificate extension &mdash; the
- * private key usage period &mdash; is not supported under the Internet
- * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this
- * method is not supported either.
+ * Returns the serial number criterion, or <code>null</code> if this
+ * value was not set.
*
- * <p>Do not use this method. It is not deprecated, as it is not deprecated
- * in the Java standard, but it is basically a no-operation.
+ * @return The serial number.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNo;
+ }
+
+ /**
+ * Get the subject alternative names criterion. The collection returned
+ * is a collection of pairs: the first element is an {@link Integer}
+ * containing the name type, and the second is a byte array containing
+ * the DER-encoded name bytes.
*
- * @param UNUSED Is silently ignored.
+ * @return The subject alternative names criterion. Returns null if this
+ * criterion is not set.
*/
- public void setPrivateKeyValid(Date UNUSED)
+ public Collection<List<?>> getSubjectAlternativeNames()
{
+ if (altNames != null)
+ {
+ List<List<?>> names = new ArrayList<List<?>>(altNames.size());
+ for (GeneralName name : altNames)
+ {
+ List<Object> n = new ArrayList<Object>(2);
+ n.add(name.kind().tag());
+ n.add(name.name());
+ names.add(n);
+ }
+ return names;
+ }
+ return null;
}
/**
- * Returns the public key algorithm ID that matching certificates must have,
- * or <code>null</code> if this criterion was not set.
+ * Returns the subject criterion as a sequence of DER bytes, or
+ * <code>null</code> if this value is not set.
*
- * @return The public key algorithm ID.
+ * @return The subject.
*/
- public String getSubjectPublicKeyAlgID()
+ public byte[] getSubjectAsBytes() throws IOException
{
- return String.valueOf(sigId);
+ if (subject != null)
+ return subject.getEncoded();
+ else
+ return null;
}
/**
- * Sets the public key algorithm ID that matching certificates must have.
- * Specify <code>null</code> to clear this criterion.
+ * Returns the subject criterion as a string, of <code>null</code> if
+ * this value was not set.
*
- * @param sigId The public key ID.
- * @throws IOException If the specified ID is not a valid object identifier.
+ * @return The subject.
*/
- public void setSubjectPublicKeyAlgID(String sigId) throws IOException
+ public String getSubjectAsString()
{
- if (sigId != null)
- {
- try
- {
- OID oid = new OID(sigId);
- int[] comp = oid.getIDs();
- if (!checkOid(comp))
- throw new IOException("malformed OID: " + sigId);
- this.sigId = oid;
- }
- catch (IllegalArgumentException iae)
- {
- IOException ioe = new IOException("malformed OID: " + sigId);
- ioe.initCause(iae);
- throw ioe;
- }
- }
+ if (subject != null)
+ return subject.getName();
else
- this.sigId = null;
+ return null;
+ }
+
+ /**
+ * Returns the subject key identifier criterion, or <code>null</code> if
+ * this value was not set. Note that the byte array is cloned to prevent
+ * modification.
+ *
+ * @return The subject key identifier.
+ */
+ public byte[] getSubjectKeyIdentifier()
+ {
+ if (subjectKeyId != null)
+ return (byte[]) subjectKeyId.clone();
+ else
+ return null;
}
/**
@@ -485,101 +552,282 @@ public class X509CertSelector implements CertSelector, Cloneable
}
/**
- * Sets the subject public key criterion as an opaque representation.
- * Specify <code>null</code> to clear this criterion.
+ * Returns the public key algorithm ID that matching certificates must have,
+ * or <code>null</code> if this criterion was not set.
*
- * @param key The public key.
+ * @return The public key algorithm ID.
*/
- public void setSubjectPublicKey(PublicKey key)
+ public String getSubjectPublicKeyAlgID()
{
- this.subjectKey = key;
- if (key == null)
- {
- subjectKeySpec = null;
- return;
- }
- try
- {
- KeyFactory enc = KeyFactory.getInstance("X.509");
- subjectKeySpec = (X509EncodedKeySpec)
- enc.getKeySpec(key, X509EncodedKeySpec.class);
- }
- catch (Exception x)
- {
- subjectKey = null;
- subjectKeySpec = null;
- }
+ return String.valueOf(sigId);
}
/**
- * Sets the subject public key criterion as a DER-encoded key. Specify
- * <code>null</code> to clear this value.
+ * Match a certificate. This method will check the given certificate
+ * against all the enabled criteria of this selector, and will return
+ * <code>true</code> if the given certificate matches.
*
- * @param key The DER-encoded key bytes.
- * @throws IOException If the argument is not a valid DER-encoded key.
+ * @param certificate The certificate to check.
+ * @return true if the certificate matches all criteria.
*/
- public void setSubjectPublicKey(byte[] key) throws IOException
+ public boolean match(Certificate certificate)
{
- if (key == null)
+ if (!(certificate instanceof X509Certificate))
+ return false;
+ X509Certificate cert = (X509Certificate) certificate;
+ if (this.cert != null)
{
- subjectKey = null;
- subjectKeySpec = null;
- return;
+ try
+ {
+ byte[] e1 = this.cert.getEncoded();
+ byte[] e2 = cert.getEncoded();
+ if (!Arrays.equals(e1, e2))
+ return false;
+ }
+ catch (CertificateEncodingException cee)
+ {
+ return false;
+ }
}
- try
+ if (serialNo != null)
{
- subjectKeySpec = new X509EncodedKeySpec(key);
- KeyFactory enc = KeyFactory.getInstance("X.509");
- subjectKey = enc.generatePublic(subjectKeySpec);
+ if (!serialNo.equals(cert.getSerialNumber()))
+ return false;
}
- catch (Exception x)
+ if (certValid != null)
{
- subjectKey = null;
- subjectKeySpec = null;
- IOException ioe = new IOException(x.getMessage());
- ioe.initCause(x);
- throw ioe;
+ try
+ {
+ cert.checkValidity(certValid);
+ }
+ catch (CertificateException ce)
+ {
+ return false;
+ }
}
+ if (issuer != null)
+ {
+ if (!issuer.equals(cert.getIssuerX500Principal()))
+ return false;
+ }
+ if (subject != null)
+ {
+ if (!subject.equals(cert.getSubjectX500Principal()))
+ return false;
+ }
+ if (sigId != null)
+ {
+ if (!sigId.toString().equals(cert.getSigAlgOID()))
+ return false;
+ }
+ if (subjectKeyId != null)
+ {
+ byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID);
+ if (!Arrays.equals(b, subjectKeyId))
+ return false;
+ }
+ if (authKeyId != null)
+ {
+ byte[] b = cert.getExtensionValue(AUTH_KEY_ID);
+ if (!Arrays.equals(b, authKeyId))
+ return false;
+ }
+ if (keyUsage != null)
+ {
+ boolean[] b = cert.getKeyUsage();
+ if (!Arrays.equals(b, keyUsage))
+ return false;
+ }
+ if (basicConstraints >= 0)
+ {
+ if (cert.getBasicConstraints() != basicConstraints)
+ return false;
+ }
+ if (keyPurposeSet != null)
+ {
+ List kp = null;
+ try
+ {
+ kp = cert.getExtendedKeyUsage();
+ }
+ catch (CertificateParsingException cpe)
+ {
+ return false;
+ }
+ if (kp == null)
+ return false;
+ for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
+ {
+ if (!kp.contains(it.next()))
+ return false;
+ }
+ }
+ if (altNames != null)
+ {
+ Collection<List<?>> an = null;
+ try
+ {
+ an = cert.getSubjectAlternativeNames();
+ }
+ catch (CertificateParsingException cpe)
+ {
+ return false;
+ }
+ if (an == null)
+ return false;
+ int match = 0;
+ for (GeneralName name : altNames)
+ {
+ for (List<?> list : an)
+ {
+ try
+ {
+ Integer id = (Integer) list.get(0);
+ Object val = list.get(1);
+ GeneralName n = null;
+ if (val instanceof String)
+ n = makeName(id, (String) val);
+ else if (val instanceof byte[])
+ {
+ n = new GeneralName(GeneralName.Kind.forTag(id),
+ (byte[]) val);
+ }
+ else
+ continue;
+ if (name.equals(n))
+ match++;
+ }
+ catch (Exception e)
+ {
+ continue;
+ }
+ }
+ if (match == 0 || (matchAllNames && match < altNames.size()))
+ return false;
+ }
+ }
+ if (nameConstraints != null)
+ {
+ byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID);
+ if (!Arrays.equals(nameConstraints, nc))
+ return false;
+ }
+
+ if (policy != null)
+ {
+ CertificatePolicies policies = null;
+ if (cert instanceof GnuPKIExtension)
+ {
+ policies = (CertificatePolicies)
+ ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID).getValue();
+ }
+ else
+ {
+ byte[] policiesDer =
+ cert.getExtensionValue(CertificatePolicies.ID.toString());
+ try
+ {
+ policies = new CertificatePolicies(policiesDer);
+ }
+ catch (IOException ioe)
+ {
+ // ignored
+ }
+ }
+
+ if (policies == null)
+ return false;
+ if (!policies.getPolicies().containsAll(policy))
+ return false;
+ }
+
+ if (pathToNames != null)
+ {
+ NameConstraints nc = null;
+ if (cert instanceof GnuPKIExtension)
+ {
+ Extension e =
+ ((GnuPKIExtension) cert).getExtension(NameConstraints.ID);
+ if (e != null)
+ nc = (NameConstraints) e.getValue();
+ }
+ else
+ {
+ byte[] b = cert.getExtensionValue(NameConstraints.ID.toString());
+ if (b != null)
+ {
+ try
+ {
+ nc = new NameConstraints(b);
+ }
+ catch (IOException ioe)
+ {
+ }
+ }
+ }
+
+ if (nc == null)
+ return false;
+
+ int match = 0;
+ for (GeneralName name : pathToNames)
+ {
+ for (GeneralSubtree subtree : nc.permittedSubtrees())
+ {
+ if (name.equals(subtree.base()))
+ match++;
+ }
+ }
+ if (match == 0 || (matchAllNames && match < pathToNames.size()))
+ return false;
+ }
+
+ return true;
}
/**
- * Returns the public key usage criterion, or <code>null</code> if this
- * value is not set. Note that the array is cloned to prevent modification.
+ * Sets the authority key identifier criterion, or <code>null</code> to clear
+ * this criterion. Note that the byte array is cloned to prevent modification.
*
- * @return The public key usage.
+ * @param authKeyId The authority key identifier.
*/
- public boolean[] getKeyUsage()
+ public void setAuthorityKeyIdentifier(byte[] authKeyId)
{
- if (keyUsage != null)
- return (boolean[]) keyUsage.clone();
- else
- return null;
+ this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null;
}
/**
- * Sets the public key usage criterion. Specify <code>null</code> to clear
- * this value.
+ * Sets the basic constraints criterion. Specify -1 to clear this parameter.
*
- * @param keyUsage The public key usage.
+ * @param basicConstraints The new basic constraints value.
*/
- public void setKeyUsage(boolean[] keyUsage)
+ public void setBasicConstraints(int basicConstraints)
{
- this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null;
+ if (basicConstraints < -1)
+ basicConstraints = -1;
+ this.basicConstraints = basicConstraints;
}
/**
- * Returns the set of extended key purpose IDs, as an unmodifiable set
- * of OID strings. Returns <code>null</code> if this criterion is not
- * set.
+ * Sets the certificate criterion. If set, only certificates that are
+ * equal to the certificate passed here will be accepted.
*
- * @return The set of key purpose OIDs (strings).
+ * @param cert The certificate.
*/
- public Set<String> getExtendedKeyUsage()
+ public void setCertificate(X509Certificate cert)
{
- if (keyPurposeSet != null)
- return Collections.unmodifiableSet(keyPurposeSet);
- else
- return null;
+ this.cert = cert;
+ }
+
+ /**
+ * Sets the date at which certificates must be valid. Specify
+ * <code>null</code> to clear this criterion.
+ *
+ * @param certValid The certificate validity date.
+ */
+ public void setCertificateValid(Date certValid)
+ {
+ this.certValid = certValid != null ? (Date) certValid.clone() : null;
}
/**
@@ -596,7 +844,7 @@ public class X509CertSelector implements CertSelector, Cloneable
this.keyPurposeSet = null;
return;
}
- Set s = new HashSet();
+ Set<String> s = new HashSet<String>();
for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
{
Object o = it.next();
@@ -620,119 +868,77 @@ public class X509CertSelector implements CertSelector, Cloneable
}
/**
- * Returns whether or not all specified alternative names must match.
- * If false, a certificate is considered a match if <em>one</em> of the
- * specified alternative names matches.
- *
- * @return true if all names must match.
- */
- public boolean getMatchAllSubjectAltNames()
- {
- return matchAllNames;
- }
-
- /**
- * Sets whether or not all subject alternative names must be matched.
- * If false, then a certificate will be considered a match if one
- * alternative name matches.
- *
- * @param matchAllNames Whether or not all alternative names must be
- * matched.
- */
- public void setMatchAllSubjectAltNames(boolean matchAllNames)
- {
- this.matchAllNames = matchAllNames;
- }
-
- /**
- * Sets the subject alternative names critertion. Each element of the
- * argument must be a {@link java.util.List} that contains exactly two
- * elements: the first an {@link Integer}, representing the type of
- * name, and the second either a {@link String} or a byte array,
- * representing the name itself.
+ * Sets the issuer, specified as the DER encoding of the issuer's
+ * distinguished name. Only certificates issued by this issuer will
+ * be accepted.
*
- * @param altNames The alternative names.
- * @throws IOException If any element of the argument is invalid.
+ * @param name The DER encoding of the issuer's distinguished name.
+ * @throws IOException If the given name is incorrectly formatted.
*/
- public void setSubjectAlternativeNames(Collection<List<?>> altNames)
- throws IOException
+ public void setIssuer(byte[] name) throws IOException
{
- if (altNames == null)
- {
- this.altNames = null;
- return;
- }
- List l = new ArrayList(altNames.size());
- for (Iterator it = altNames.iterator(); it.hasNext(); )
+ if (name != null)
{
- Object o = it.next();
- if (!(o instanceof List) || ((List) o).size() != 2 ||
- !(((List) o).get(0) instanceof Integer) ||
- !(((List) o).get(1) instanceof String) ||
- !(((List) o).get(1) instanceof byte[]))
- throw new IOException("illegal alternative name: " + o);
- Integer i = (Integer) ((List) o).get(0);
- if (i.intValue() < 0 || i.intValue() > 8)
- throw new IOException("illegal alternative name: " + o +
- ", bad id: " + i);
- l.add(new ArrayList((List) o));
+ try
+ {
+ issuer = new X500Principal(name);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ throw new IOException(iae.getMessage());
+ }
}
- this.altNames = l;
+ else
+ issuer = null;
}
/**
- * Add a name to the subject alternative names criterion.
+ * Sets the issuer, specified as a string representation of the issuer's
+ * distinguished name. Only certificates issued by this issuer will
+ * be accepted.
*
- * @param id The type of name this is. Must be in the range [0,8].
- * @param name The name.
- * @throws IOException If the id is out of range, or if the name
- * is null.
+ * @param name The string representation of the issuer's distinguished name.
+ * @throws IOException If the given name is incorrectly formatted.
*/
- public void addSubjectAlternativeName(int id, String name)
- throws IOException
+ public void setIssuer(String name) throws IOException
{
- if (id < 0 || id > 8 || name == null)
- throw new IOException("illegal alternative name");
- if (altNames == null)
- altNames = new LinkedList();
- ArrayList l = new ArrayList(2);
- l.add(Integer.valueOf(id));
- l.add(name);
- altNames.add(l);
+ if (name != null)
+ {
+ try
+ {
+ issuer = new X500Principal(name);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ throw new IOException(iae.getMessage());
+ }
+ }
+ else
+ issuer = null;
}
/**
- * Add a name, as DER-encoded bytes, to the subject alternative names
- * criterion.
+ * Sets the public key usage criterion. Specify <code>null</code> to clear
+ * this value.
*
- * @param id The type of name this is.
+ * @param keyUsage The public key usage.
*/
- public void addSubjectAlternativeName(int id, byte[] name)
- throws IOException
+ public void setKeyUsage(boolean[] keyUsage)
{
- if (id < 0 || id > 8 || name == null)
- throw new IOException("illegal alternative name");
- if (altNames == null)
- altNames = new LinkedList();
- ArrayList l = new ArrayList(2);
- l.add(Integer.valueOf(id));
- l.add(name);
- altNames.add(l);
+ this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null;
}
/**
- * Returns the name constraints criterion, or <code>null</code> if this
- * value is not set. Note that the byte array is cloned to prevent
- * modification.
+ * Sets whether or not all subject alternative names must be matched.
+ * If false, then a certificate will be considered a match if one
+ * alternative name matches.
*
- * @return The name constraints.
+ * @param matchAllNames Whether or not all alternative names must be
+ * matched.
*/
- public byte[] getNameConstraints()
+ public void setMatchAllSubjectAltNames(boolean matchAllNames)
{
- if (nameConstraints != null)
- return (byte[]) nameConstraints.clone();
- else
- return null;
+ this.matchAllNames = matchAllNames;
}
/**
@@ -747,280 +953,302 @@ public class X509CertSelector implements CertSelector, Cloneable
public void setNameConstraints(byte[] nameConstraints)
throws IOException
{
- // FIXME check if the argument is valid.
+ // Check if the input is well-formed...
+ new NameConstraints(nameConstraints);
+
+ // But we just compare raw byte arrays.
this.nameConstraints = nameConstraints != null
? (byte[]) nameConstraints.clone() : null;
}
+
+ /**
+ * Sets the pathToNames criterion. The argument is a collection of
+ * pairs, the first element of which is an {@link Integer} giving
+ * the ID of the name, and the second element is either a {@link String}
+ * or a byte array.
+ *
+ * See {@link #addPathToName(int, byte[])} and {@link #addPathToName(int, String)}
+ * for how these arguments are handled.
+ *
+ * @param names The names.
+ * @throws IOException If any argument is malformed.
+ */
+ public void setPathToNames(Collection<List<?>> names) throws IOException
+ {
+ if (names == null || names.size() == 0)
+ {
+ pathToNames = null;
+ }
+ else
+ {
+ pathToNames = new ArrayList<GeneralName>(names.size());
+ for (List<?> name : names)
+ {
+ Integer id = (Integer) name.get(0);
+ Object name2 = name.get(1);
+ if (name2 instanceof String)
+ addPathToName(id, (String) name2);
+ else if (name2 instanceof byte[])
+ addPathToName(id, (byte[]) name2);
+ else
+ throw new IOException("invalid name type: "
+ + name2.getClass().getName());
+ }
+ }
+ }
/**
- * Returns the basic constraints criterion, or -1 if this value is not set.
+ * Sets the certificate policy to match, or null if this criterion should
+ * not be checked. Each element if the set must be a dotted-decimal form
+ * of certificate policy object identifier.
*
- * @return The basic constraints.
+ * @param policy The policy to match.
+ * @throws IOException If some element of the policy is not a valid
+ * policy extenison OID.
*/
- public int getBasicConstraints()
+ public void setPolicy(Set<String> policy) throws IOException
{
- return basicConstraints;
+ if (policy != null)
+ {
+ HashSet<OID> p = new HashSet<OID>(policy.size());
+ for (String s : policy)
+ {
+ try
+ {
+ OID oid = new OID(s);
+ int[] i = oid.getIDs();
+ if (!checkOid(i))
+ throw new IOException("invalid OID");
+ p.add(oid);
+ }
+ catch (IOException ioe)
+ {
+ throw ioe;
+ }
+ catch (Exception x)
+ {
+ IOException ioe = new IOException("invalid OID");
+ ioe.initCause(x);
+ throw ioe;
+ }
+ }
+ this.policy = p;
+ }
+ else
+ this.policy = null;
}
/**
- * Sets the basic constraints criterion. Specify -1 to clear this parameter.
+ * This method, and its related X.509 certificate extension &mdash; the
+ * private key usage period &mdash; is not supported under the Internet
+ * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this
+ * method is not supported either.
*
- * @param basicConstraints The new basic constraints value.
+ * <p>Do not use this method. It is not deprecated, as it is not deprecated
+ * in the Java standard, but it is basically a no-operation.
+ *
+ * @param UNUSED Is silently ignored.
*/
- public void setBasicConstraints(int basicConstraints)
+ public void setPrivateKeyValid(Date UNUSED)
{
- if (basicConstraints < -1)
- basicConstraints = -1;
- this.basicConstraints = basicConstraints;
}
- // The last two criteria not yet implemented are certificate policies
- // and path-to-names. Both of these are somewhat advanced extensions
- // (you could probably count the applications that actually use them
- // on one hand), and they both have no support in the X509Certificate
- // class.
- //
- // Not having support in X509Certificate is not always a problem; for
- // example, we can compare DER-encoded values as byte arrays for some
- // extensions. We can't, however, compare them if they are specified
- // in a set (as policies are). We need to parse the actual value in the
- // certificate, and check it against the specified set.
-
- // FIXME
-// public void setPolicy(Set<String> policy) throws IOException
-// {
-// if (policy != null)
-// {
-// for (Iterator it = policy.iterator(); it.hasNext(); )
-// try
-// {
-// OID oid = new OID((String) it.next());
-// int[] i = oid.getIDs();
-// if (!checkOid(i))
-// throw new IOException("invalid OID");
-// }
-// catch (Exception x)
-// {
-// throw new IOException("invalid OID");
-// }
-// }
-// this.policy = policy != null ? new HashSet(policy) : null;
-// }
-
- // FIXME
-// public void setPathToNames(Collection<List<?>> names) throws IOException
-// {
-// if (names == null)
-// {
-// this.names = null;
-// return;
-// }
-// for (Iterator it = names.iterator(); it.hasNext(); )
-// {
-// try
-// {
-// List l = (List) it.next();
-// if (l.get(1) instanceof String)
-// addPathToName(((Integer)l.get(0)).intValue(), (String)l.get(1));
-// else
-// addPathToName(((Integer)l.get(0)).intValue(), (byte[])l.get(1));
-// }
-// catch (Exception x)
-// {
-// this.names = null;
-// throw new IOException("invalid names");
-// }
-// }
-// }
-
- // FIXME
-// public void addPathToName(int id, String name) throws IOException
-// {
-// }
-
- // FIXME
-// public void addPathToName(int id, byte[] name) throws IOException
-// {
-// }
-
- // FIXME
-// public Collection<List<?>> getSubjectAlternativeNames()
-// {
-// return null;
-// }
-
- // FIXME
-// public Set<String> getPolicy()
-// {
-// return null;
-// }
-
- // FIXME
-// public Collection<List<?>> getPathToNames()
-// {
-// return null;
-// }
+ /**
+ * Sets the serial number of the desired certificate. Only certificates that
+ * contain this serial number are accepted.
+ *
+ * @param serialNo The serial number.
+ */
+ public void setSerialNumber(BigInteger serialNo)
+ {
+ this.serialNo = serialNo;
+ }
/**
- * Match a certificate. This method will check the given certificate
- * against all the enabled criteria of this selector, and will return
- * <code>true</code> if the given certificate matches.
+ * Sets the subject, specified as the DER encoding of the subject's
+ * distinguished name. Only certificates with the given subject will
+ * be accepted.
*
- * @param certificate The certificate to check.
- * @return true if the certificate matches all criteria.
+ * @param name The DER encoding of the subject's distinguished name.
+ * @throws IOException If the given name is incorrectly formatted.
*/
- public boolean match(Certificate certificate)
+ public void setSubject(byte[] name) throws IOException
{
- if (!(certificate instanceof X509Certificate))
- return false;
- X509Certificate cert = (X509Certificate) certificate;
- if (this.cert != null)
+ if (name != null)
{
try
{
- byte[] e1 = this.cert.getEncoded();
- byte[] e2 = cert.getEncoded();
- if (!Arrays.equals(e1, e2))
- return false;
+ subject = new X500Principal(name);
}
- catch (CertificateEncodingException cee)
+ catch (IllegalArgumentException iae)
{
- return false;
+ throw new IOException(iae.getMessage());
}
}
- if (serialNo != null)
- {
- if (!serialNo.equals(cert.getSerialNumber()))
- return false;
- }
- if (certValid != null)
+ else
+ subject = null;
+ }
+
+ /**
+ * Sets the subject, specified as a string representation of the
+ * subject's distinguished name. Only certificates with the given
+ * subject will be accepted.
+ *
+ * @param name The string representation of the subject's distinguished name.
+ * @throws IOException If the given name is incorrectly formatted.
+ */
+ public void setSubject(String name) throws IOException
+ {
+ if (name != null)
{
try
{
- cert.checkValidity(certValid);
+ subject = new X500Principal(name);
}
- catch (CertificateException ce)
+ catch (IllegalArgumentException iae)
{
- return false;
+ throw new IOException(iae.getMessage());
}
}
- if (issuer != null)
+ else
+ subject = null;
+ }
+
+ /**
+ * Sets the subject alternative names critertion. Each element of the
+ * argument must be a {@link java.util.List} that contains exactly two
+ * elements: the first an {@link Integer}, representing the type of
+ * name, and the second either a {@link String} or a byte array,
+ * representing the name itself.
+ *
+ * @param altNames The alternative names.
+ * @throws IOException If any element of the argument is invalid.
+ */
+ public void setSubjectAlternativeNames(Collection<List<?>> altNames)
+ throws IOException
+ {
+ if (altNames == null || altNames.isEmpty())
{
- if (!issuer.equals(cert.getIssuerX500Principal()))
- return false;
+ this.altNames = null;
+ return;
}
- if (subject != null)
+ List<GeneralName> l = new ArrayList<GeneralName>(altNames.size());
+ for (List<?> list : altNames)
{
- if (!subject.equals(cert.getSubjectX500Principal()))
- return false;
+ Integer id = (Integer) list.get(0);
+ Object value = list.get(1);
+ GeneralName name = null;
+ if (value instanceof String)
+ name = makeName(id, (String) value);
+ else if (value instanceof byte[])
+ name = new GeneralName(GeneralName.Kind.forTag(id), (byte[]) value);
+ else
+ throw new IOException("invalid name type: " + value.getClass().getName());
+ l.add(name);
}
- if (sigId != null)
+ this.altNames = l;
+ }
+
+ /**
+ * Sets the subject key identifier criterion, or <code>null</code> to clear
+ * this criterion. Note that the byte array is cloned to prevent modification.
+ *
+ * @param subjectKeyId The subject key identifier.
+ */
+ public void setSubjectKeyIdentifier(byte[] subjectKeyId)
+ {
+ this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() :
+ null;
+ }
+
+ /**
+ * Sets the subject public key criterion as a DER-encoded key. Specify
+ * <code>null</code> to clear this value.
+ *
+ * @param key The DER-encoded key bytes.
+ * @throws IOException If the argument is not a valid DER-encoded key.
+ */
+ public void setSubjectPublicKey(byte[] key) throws IOException
+ {
+ if (key == null)
{
- if (!sigId.toString().equals(cert.getSigAlgOID()))
- return false;
+ subjectKey = null;
+ subjectKeySpec = null;
+ return;
}
- if (subjectKeyId != null)
+ try
{
- byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID);
- if (!Arrays.equals(b, subjectKeyId))
- return false;
+ subjectKeySpec = new X509EncodedKeySpec(key);
+ KeyFactory enc = KeyFactory.getInstance("X.509");
+ subjectKey = enc.generatePublic(subjectKeySpec);
}
- if (authKeyId != null)
+ catch (Exception x)
{
- byte[] b = cert.getExtensionValue(AUTH_KEY_ID);
- if (!Arrays.equals(b, authKeyId))
- return false;
+ subjectKey = null;
+ subjectKeySpec = null;
+ IOException ioe = new IOException(x.getMessage());
+ ioe.initCause(x);
+ throw ioe;
}
- if (keyUsage != null)
+ }
+
+ /**
+ * Sets the subject public key criterion as an opaque representation.
+ * Specify <code>null</code> to clear this criterion.
+ *
+ * @param key The public key.
+ */
+ public void setSubjectPublicKey(PublicKey key)
+ {
+ this.subjectKey = key;
+ if (key == null)
{
- boolean[] b = cert.getKeyUsage();
- if (!Arrays.equals(b, keyUsage))
- return false;
+ subjectKeySpec = null;
+ return;
}
- if (basicConstraints >= 0)
+ try
{
- if (cert.getBasicConstraints() != basicConstraints)
- return false;
+ KeyFactory enc = KeyFactory.getInstance("X.509");
+ subjectKeySpec = (X509EncodedKeySpec)
+ enc.getKeySpec(key, X509EncodedKeySpec.class);
}
- if (keyPurposeSet != null)
+ catch (Exception x)
{
- List kp = null;
- try
- {
- kp = cert.getExtendedKeyUsage();
- }
- catch (CertificateParsingException cpe)
- {
- return false;
- }
- if (kp == null)
- return false;
- for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
- {
- if (!kp.contains(it.next()))
- return false;
- }
+ subjectKey = null;
+ subjectKeySpec = null;
}
- if (altNames != null)
+ }
+
+ /**
+ * Sets the public key algorithm ID that matching certificates must have.
+ * Specify <code>null</code> to clear this criterion.
+ *
+ * @param sigId The public key ID.
+ * @throws IOException If the specified ID is not a valid object identifier.
+ */
+ public void setSubjectPublicKeyAlgID(String sigId) throws IOException
+ {
+ if (sigId != null)
{
- Collection an = null;
try
{
- an = cert.getSubjectAlternativeNames();
- }
- catch (CertificateParsingException cpe)
- {
- return false;
+ OID oid = new OID(sigId);
+ int[] comp = oid.getIDs();
+ if (!checkOid(comp))
+ throw new IOException("malformed OID: " + sigId);
+ this.sigId = oid;
}
- if (an == null)
- return false;
- int match = 0;
- for (Iterator it = altNames.iterator(); it.hasNext(); )
+ catch (IllegalArgumentException iae)
{
- List l = (List) it.next();
- Integer id = (Integer) l.get(0);
- String s = null;
- byte[] b = null;
- if (l.get(1) instanceof String)
- s = (String) l.get(1);
- else if (l.get(1) instanceof byte[])
- b = (byte[]) l.get(1);
- else
- return false;
- for (Iterator it2 = an.iterator(); it2.hasNext(); )
- {
- Object o = it2.next();
- if (!(o instanceof List))
- continue;
- List l2 = (List) o;
- if (l2.size() != 2)
- continue;
- if (!id.equals(l2.get(0)))
- continue;
- if (s != null && (l2.get(1) instanceof String) &&
- s.equals(l2.get(1)))
- match++;
- else if (b != null && (l2.get(1) instanceof byte[]) &&
- Arrays.equals(b, (byte[]) l2.get(1)))
- match++;
- }
- if (match == 0 || (matchAllNames && match != altNames.size()))
- return false;
+ IOException ioe = new IOException("malformed OID: " + sigId);
+ ioe.initCause(iae);
+ throw ioe;
}
}
- if (nameConstraints != null)
- {
- byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID);
- if (!Arrays.equals(nameConstraints, nc))
- return false;
- }
-
- // FIXME check policies.
- // FIXME check path-to-names.
-
- return true;
+ else
+ this.sigId = null;
}
-
+
public String toString()
{
StringBuffer str = new StringBuffer(X509CertSelector.class.getName());
@@ -1080,28 +1308,11 @@ public class X509CertSelector implements CertSelector, Cloneable
str.append(" alternative names = ").append(altNames).append(eol);
if (nameConstraints != null)
str.append(" name constraints = <blob of data>").append(eol);
+ if (policy != null)
+ str.append(" policy = ").append(policy).append(eol);
+ if (pathToNames != null)
+ str.append(" pathToNames = ").append(pathToNames).append(eol);
str.append("}").append(nl);
return str.toString();
}
-
- public Object clone()
- {
- try
- {
- return super.clone();
- }
- catch (CloneNotSupportedException shouldNotHappen)
- {
- throw new Error(shouldNotHappen);
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private static boolean checkOid(int[] oid)
- {
- return (oid != null && oid.length > 2 &&
- (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39));
- }
}
diff --git a/libjava/classpath/java/security/cert/X509Certificate.java b/libjava/classpath/java/security/cert/X509Certificate.java
index bc1b5c2351c..b398e093e6a 100644
--- a/libjava/classpath/java/security/cert/X509Certificate.java
+++ b/libjava/classpath/java/security/cert/X509Certificate.java
@@ -1,5 +1,5 @@
/* X509Certificate.java --- X.509 Certificate class
- Copyright (C) 1999,2003 Free Software Foundation, Inc.
+ Copyright (C) 1999,2003, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -137,7 +137,7 @@ import java.util.List;
* @author Casey Marshall (rsdio@metastatic.org)
*/
public abstract class X509Certificate
- extends java.security.cert.Certificate // XXX workaround for gcj bug #17845
+ extends Certificate
implements X509Extension
{
private static final long serialVersionUID = -2491127588187038216L;
diff --git a/libjava/classpath/java/text/AttributedStringIterator.java b/libjava/classpath/java/text/AttributedStringIterator.java
index 422876c0948..2f970feba43 100644
--- a/libjava/classpath/java/text/AttributedStringIterator.java
+++ b/libjava/classpath/java/text/AttributedStringIterator.java
@@ -213,9 +213,7 @@ class AttributedStringIterator implements AttributedCharacterIterator
Iterator iterator = attributeSet.iterator();
while (iterator.hasNext())
{
- // Qualified name is a workaround for a gcj 4.0 bug.
- AttributedCharacterIterator.Attribute attributeKey
- = (AttributedCharacterIterator.Attribute) iterator.next();
+ Attribute attributeKey = (Attribute) iterator.next();
Object v1 = runValues.get(attributeKey);
Object v2 = getAttribute(attributeKey, limit + 1);
boolean changed = false;
@@ -298,9 +296,7 @@ class AttributedStringIterator implements AttributedCharacterIterator
Iterator iterator = attributeSet.iterator();
while (iterator.hasNext())
{
- // Qualified name is a workaround for a gcj 4.0 bug.
- AttributedCharacterIterator.Attribute attributeKey
- = (AttributedCharacterIterator.Attribute) iterator.next();
+ Attribute attributeKey = (Attribute) iterator.next();
Object v1 = runValues.get(attributeKey);
Object v2 = getAttribute(attributeKey, prev);
boolean changed = false;
diff --git a/libjava/classpath/java/text/BreakIterator.java b/libjava/classpath/java/text/BreakIterator.java
index 7ba116870de..30e5f2b9491 100644
--- a/libjava/classpath/java/text/BreakIterator.java
+++ b/libjava/classpath/java/text/BreakIterator.java
@@ -1,5 +1,6 @@
/* BreakIterator.java -- Breaks text into elements
- Copyright (C) 1998, 1999, 2001, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2001, 2004, 2005, 2007
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,9 +39,19 @@ exception statement from your version. */
package java.text;
+import gnu.java.locale.LocaleHelper;
+
+import gnu.java.text.CharacterBreakIterator;
+import gnu.java.text.LineBreakIterator;
+import gnu.java.text.SentenceBreakIterator;
+import gnu.java.text.WordBreakIterator;
+
+import java.text.spi.BreakIteratorProvider;
+
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.ServiceLoader;
/**
* This class iterates over text elements such as words, lines, sentences,
@@ -179,19 +190,34 @@ public abstract class BreakIterator implements Cloneable
/**
* This method returns an instance of <code>BreakIterator</code> that will
- * iterate over characters as defined in the specified locale. If the
- * desired locale is not available, the default locale is used.
+ * iterate over characters as defined in the specified locale.
*
* @param locale The desired locale.
*
- * @return A <code>BreakIterator</code> instance for the default locale.
+ * @return A <code>BreakIterator</code> instance for the specified locale.
*/
public static BreakIterator getCharacterInstance (Locale locale)
{
- BreakIterator r = getInstance ("CharacterIterator", locale);
- if (r == null)
- r = new gnu.java.text.CharacterBreakIterator ();
- return r;
+ BreakIterator r = getInstance("CharacterIterator", locale);
+ if (r != null)
+ return r;
+ for (BreakIteratorProvider p :
+ ServiceLoader.load(BreakIteratorProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ BreakIterator bi = p.getCharacterInstance(locale);
+ if (bi != null)
+ return bi;
+ break;
+ }
+ }
+ }
+ if (locale.equals(Locale.ROOT))
+ return new CharacterBreakIterator();
+ return getCharacterInstance(LocaleHelper.getFallbackLocale(locale));
}
/**
@@ -207,8 +233,7 @@ public abstract class BreakIterator implements Cloneable
/**
* This method returns an instance of <code>BreakIterator</code> that will
- * iterate over line breaks as defined in the specified locale. If the
- * desired locale is not available, the default locale is used.
+ * iterate over line breaks as defined in the specified locale.
*
* @param locale The desired locale.
*
@@ -217,9 +242,25 @@ public abstract class BreakIterator implements Cloneable
public static BreakIterator getLineInstance (Locale locale)
{
BreakIterator r = getInstance ("LineIterator", locale);
- if (r == null)
- r = new gnu.java.text.LineBreakIterator ();
- return r;
+ if (r != null)
+ return r;
+ for (BreakIteratorProvider p :
+ ServiceLoader.load(BreakIteratorProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ BreakIterator bi = p.getLineInstance(locale);
+ if (bi != null)
+ return bi;
+ break;
+ }
+ }
+ }
+ if (locale.equals(Locale.ROOT))
+ return new LineBreakIterator();
+ return getLineInstance(LocaleHelper.getFallbackLocale(locale));
}
/**
@@ -235,8 +276,7 @@ public abstract class BreakIterator implements Cloneable
/**
* This method returns an instance of <code>BreakIterator</code> that will
- * iterate over sentences as defined in the specified locale. If the
- * desired locale is not available, the default locale is used.
+ * iterate over sentences as defined in the specified locale.
*
* @param locale The desired locale.
*
@@ -245,9 +285,25 @@ public abstract class BreakIterator implements Cloneable
public static BreakIterator getSentenceInstance (Locale locale)
{
BreakIterator r = getInstance ("SentenceIterator", locale);
- if (r == null)
- r = new gnu.java.text.SentenceBreakIterator ();
- return r;
+ if (r != null)
+ return r;
+ for (BreakIteratorProvider p :
+ ServiceLoader.load(BreakIteratorProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ BreakIterator bi = p.getSentenceInstance(locale);
+ if (bi != null)
+ return bi;
+ break;
+ }
+ }
+ }
+ if (locale.equals(Locale.ROOT))
+ return new SentenceBreakIterator();
+ return getSentenceInstance(LocaleHelper.getFallbackLocale(locale));
}
/**
@@ -271,8 +327,7 @@ public abstract class BreakIterator implements Cloneable
/**
* This method returns an instance of <code>BreakIterator</code> that will
- * iterate over words as defined in the specified locale. If the
- * desired locale is not available, the default locale is used.
+ * iterate over words as defined in the specified locale.
*
* @param locale The desired locale.
*
@@ -281,9 +336,25 @@ public abstract class BreakIterator implements Cloneable
public static BreakIterator getWordInstance (Locale locale)
{
BreakIterator r = getInstance ("WordIterator", locale);
- if (r == null)
- r = new gnu.java.text.WordBreakIterator ();
- return r;
+ if (r != null)
+ return r;
+ for (BreakIteratorProvider p :
+ ServiceLoader.load(BreakIteratorProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ BreakIterator bi = p.getWordInstance(locale);
+ if (bi != null)
+ return bi;
+ break;
+ }
+ }
+ }
+ if (locale.equals(Locale.ROOT))
+ return new WordBreakIterator();
+ return getWordInstance(LocaleHelper.getFallbackLocale(locale));
}
/**
diff --git a/libjava/classpath/java/text/Collator.java b/libjava/classpath/java/text/Collator.java
index 95236132440..16ee6b1241b 100644
--- a/libjava/classpath/java/text/Collator.java
+++ b/libjava/classpath/java/text/Collator.java
@@ -40,10 +40,13 @@ package java.text;
import gnu.java.locale.LocaleHelper;
+import java.text.spi.CollatorProvider;
+
import java.util.Comparator;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.ServiceLoader;
/**
* This class is the abstract superclass of classes which perform
@@ -285,7 +288,8 @@ public abstract class Collator implements Comparator<Object>, Cloneable
/**
* This method returns an instance of <code>Collator</code> for the
* specified locale. If no <code>Collator</code> exists for the desired
- * locale, a <code>Collator</code> for the default locale will be returned.
+ * locale, the fallback procedure described in
+ * {@link java.util.spi.LocaleServiceProvider} is invoked.
*
* @param loc The desired locale to load a <code>Collator</code> for.
*
@@ -293,27 +297,51 @@ public abstract class Collator implements Comparator<Object>, Cloneable
*/
public static Collator getInstance (Locale loc)
{
- ResourceBundle res;
String pattern;
try
{
- res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
- loc, ClassLoader.getSystemClassLoader());
- pattern = res.getString("collation_rules");
+ ResourceBundle res =
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ loc, ClassLoader.getSystemClassLoader());
+ return new RuleBasedCollator(res.getString("collation_rules"));
}
catch (MissingResourceException x)
{
- pattern = "<0<1<2<3<4<5<6<7<8<9<A,a<b,B<c,C<d,D<e,E<f,F<g,G<h,H<i,I<j,J<k,K" +
- "<l,L<m,M<n,N<o,O<p,P<q,Q<r,R<s,S<t,T<u,U<v,V<w,W<x,X<y,Y<z,Z";
- }
- try
- {
- return new RuleBasedCollator (pattern);
+ /* This means runtime support for the locale
+ * is not available, so we check providers. */
}
catch (ParseException x)
{
throw (InternalError)new InternalError().initCause(x);
}
+ for (CollatorProvider p : ServiceLoader.load(CollatorProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(loc))
+ {
+ Collator c = p.getInstance(loc);
+ if (c != null)
+ return c;
+ break;
+ }
+ }
+ }
+ if (loc.equals(Locale.ROOT))
+ {
+ try
+ {
+ return new RuleBasedCollator("<0<1<2<3<4<5<6<7<8<9<A,a<b,B<c," +
+ "C<d,D<e,E<f,F<g,G<h,H<i,I<j,J<k,K" +
+ "<l,L<m,M<n,N<o,O<p,P<q,Q<r,R<s,S<t,"+
+ "T<u,U<v,V<w,W<x,X<y,Y<z,Z");
+ }
+ catch (ParseException x)
+ {
+ throw (InternalError)new InternalError().initCause(x);
+ }
+ }
+ return getInstance(LocaleHelper.getFallbackLocale(loc));
}
/**
diff --git a/libjava/classpath/java/text/DateFormat.java b/libjava/classpath/java/text/DateFormat.java
index 73aa62d9805..53b757e88b6 100644
--- a/libjava/classpath/java/text/DateFormat.java
+++ b/libjava/classpath/java/text/DateFormat.java
@@ -39,12 +39,17 @@ exception statement from your version. */
package java.text;
+import gnu.java.locale.LocaleHelper;
+
+import java.text.spi.DateFormatProvider;
+
import java.io.InvalidObjectException;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.ServiceLoader;
import java.util.TimeZone;
/**
@@ -550,17 +555,14 @@ public abstract class DateFormat extends Format implements Cloneable
private static DateFormat computeInstance (int dateStyle, int timeStyle,
Locale loc, boolean use_date,
boolean use_time)
+ throws MissingResourceException
{
- ResourceBundle res;
- try
- {
- res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
- loc, ClassLoader.getSystemClassLoader());
- }
- catch (MissingResourceException x)
- {
- res = null;
- }
+ if (loc.equals(Locale.ROOT))
+ return computeDefault(dateStyle,timeStyle,use_date,use_time);
+
+ ResourceBundle res =
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ loc, ClassLoader.getSystemClassLoader());
String pattern = null;
if (use_date)
@@ -642,6 +644,59 @@ public abstract class DateFormat extends Format implements Cloneable
return new SimpleDateFormat (pattern, loc);
}
+ private static DateFormat computeDefault (int dateStyle, int timeStyle,
+ boolean use_date, boolean use_time)
+ {
+ String pattern = null;
+ if (use_date)
+ {
+ switch (dateStyle)
+ {
+ case FULL:
+ pattern = "EEEE MMMM d, yyyy G";
+ break;
+ case LONG:
+ pattern = "MMMM d, yyyy";
+ break;
+ case MEDIUM:
+ pattern = "d-MMM-yy";
+ break;
+ case SHORT:
+ pattern = "M/d/yy";
+ default:
+ throw new IllegalArgumentException ();
+ }
+ }
+
+ if (use_time)
+ {
+ if (pattern == null)
+ pattern = "";
+ else
+ pattern += " ";
+
+ switch (timeStyle)
+ {
+ case FULL:
+ pattern += "h:mm:ss;S 'o''clock' a z";
+ break;
+ case LONG:
+ pattern += "h:mm:ss a z";
+ break;
+ case MEDIUM:
+ pattern += "h:mm:ss a";
+ break;
+ case SHORT:
+ pattern += "h:mm a";
+ break;
+ default:
+ throw new IllegalArgumentException ();
+ }
+ }
+
+ return new SimpleDateFormat (pattern, Locale.ROOT);
+ }
+
/**
* This method returns an instance of <code>DateFormat</code> that will
* format using the default formatting style for dates.
@@ -678,7 +733,29 @@ public abstract class DateFormat extends Format implements Cloneable
*/
public static final DateFormat getDateInstance (int style, Locale loc)
{
- return computeInstance (style, loc, true, false);
+ try
+ {
+ return computeInstance (style, loc, true, false);
+ }
+ catch (MissingResourceException e)
+ {
+ for (DateFormatProvider p :
+ ServiceLoader.load(DateFormatProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(loc))
+ {
+ DateFormat df = p.getDateInstance(style, loc);
+ if (df != null)
+ return df;
+ break;
+ }
+ }
+ }
+ return getDateInstance(style,
+ LocaleHelper.getFallbackLocale(loc));
+ }
}
/**
@@ -717,7 +794,30 @@ public abstract class DateFormat extends Format implements Cloneable
int timeStyle,
Locale loc)
{
- return computeInstance (dateStyle, timeStyle, loc, true, true);
+ try
+ {
+ return computeInstance (dateStyle, timeStyle, loc, true, true);
+ }
+ catch (MissingResourceException e)
+ {
+ for (DateFormatProvider p :
+ ServiceLoader.load(DateFormatProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(loc))
+ {
+ DateFormat df = p.getDateTimeInstance(dateStyle,
+ timeStyle, loc);
+ if (df != null)
+ return df;
+ break;
+ }
+ }
+ }
+ return getDateTimeInstance(dateStyle, timeStyle,
+ LocaleHelper.getFallbackLocale(loc));
+ }
}
/**
@@ -779,7 +879,29 @@ public abstract class DateFormat extends Format implements Cloneable
*/
public static final DateFormat getTimeInstance (int style, Locale loc)
{
- return computeInstance (style, loc, false, true);
+ try
+ {
+ return computeInstance (style, loc, false, true);
+ }
+ catch (MissingResourceException e)
+ {
+ for (DateFormatProvider p :
+ ServiceLoader.load(DateFormatProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(loc))
+ {
+ DateFormat df = p.getTimeInstance(style, loc);
+ if (df != null)
+ return df;
+ break;
+ }
+ }
+ }
+ return getTimeInstance(style,
+ LocaleHelper.getFallbackLocale(loc));
+ }
}
/**
diff --git a/libjava/classpath/java/text/DateFormatSymbols.java b/libjava/classpath/java/text/DateFormatSymbols.java
index bffd31fb6a7..406376a0ff5 100644
--- a/libjava/classpath/java/text/DateFormatSymbols.java
+++ b/libjava/classpath/java/text/DateFormatSymbols.java
@@ -1,5 +1,5 @@
/* DateFormatSymbols.java -- Format over a range of numbers
- Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,14 +38,26 @@ exception statement from your version. */
package java.text;
+import gnu.java.locale.LocaleHelper;
+
+import java.text.spi.DateFormatSymbolsProvider;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.ServiceLoader;
+import java.util.TimeZone;
+
+import java.util.spi.TimeZoneNameProvider;
/**
* This class acts as container for locale specific date/time formatting
* information such as the days of the week and the months of the year.
+ *
* @author Per Bothner (bothner@cygnus.com)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
* @date October 24, 1998.
*/
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3.
@@ -60,6 +72,15 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
String[] shortMonths;
String[] shortWeekdays;
String[] weekdays;
+
+ /**
+ * The timezone strings supplied by the runtime.
+ */
+ private String[][] runtimeZoneStrings;
+
+ /**
+ * Custom timezone strings supplied by {@link #setZoneStrings()}.
+ */
private String[][] zoneStrings;
private static final long serialVersionUID = -5987973545549424702L;
@@ -83,22 +104,52 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
return res.getString(name).split("\u00ae");
}
- private String[][] getZoneStrings(ResourceBundle res)
+ private String[][] getZoneStrings(ResourceBundle res, Locale locale)
{
+ List<String[]> allZones = new ArrayList<String[]>();
try
{
int index = 0;
String data = res.getString("zoneStrings");
String[] zones = data.split("\u00a9");
- String[][] array = new String[zones.length][];
for (int a = 0; a < zones.length; ++a)
- array[a] = zones[a].split("\u00ae");
- return array;
+ allZones.add(zones[a].split("\u00ae"));
}
catch (MissingResourceException e)
{
- return new String[0][];
+ /* This means runtime support for the locale
+ * is not available, so we just include providers. */
}
+ for (TimeZoneNameProvider p :
+ ServiceLoader.load(TimeZoneNameProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ for (String id : TimeZone.getAvailableIDs())
+ {
+ String[] z = new String[5];
+ z[0] = id;
+ z[1] = p.getDisplayName(id, false,
+ TimeZone.LONG,
+ locale);
+ z[2] = p.getDisplayName(id, false,
+ TimeZone.SHORT,
+ locale);
+ z[3] = p.getDisplayName(id, true,
+ TimeZone.LONG,
+ locale);
+ z[4] = p.getDisplayName(id, true,
+ TimeZone.SHORT,
+ locale);
+ allZones.add(z);
+ }
+ break;
+ }
+ }
+ }
+ return allZones.toArray(new String[allZones.size()][]);
}
private String[] formatsForKey(ResourceBundle res, String key)
@@ -114,11 +165,18 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
/**
* This method initializes a new instance of <code>DateFormatSymbols</code>
* by loading the date format information for the specified locale.
+ * This constructor only obtains instances using the runtime's resources;
+ * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances,
+ * call {@link #getInstance(java.util.Locale)} instead.
*
* @param locale The locale for which date formatting symbols should
* be loaded.
+ * @throws MissingResourceException if the resources for the specified
+ * locale could not be found or loaded.
+ * @see #getInstance(java.util.Locale)
*/
- public DateFormatSymbols (Locale locale) throws MissingResourceException
+ public DateFormatSymbols (Locale locale)
+ throws MissingResourceException
{
ResourceBundle res
= ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale,
@@ -131,16 +189,23 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
shortMonths = getStringArray(res, "shortMonths");
shortWeekdays = getStringArray(res, "shortWeekdays");
weekdays = getStringArray(res, "weekdays");
- zoneStrings = getZoneStrings(res);
+ runtimeZoneStrings = getZoneStrings(res, locale);
dateFormats = formatsForKey(res, "DateFormat");
timeFormats = formatsForKey(res, "TimeFormat");
}
/**
* This method loads the format symbol information for the default
- * locale.
+ * locale. This constructor only obtains instances using the runtime's resources;
+ * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances,
+ * call {@link #getInstance()} instead.
+ *
+ * @throws MissingResourceException if the resources for the default
+ * locale could not be found or loaded.
+ * @see #getInstance()
*/
- public DateFormatSymbols () throws MissingResourceException
+ public DateFormatSymbols()
+ throws MissingResourceException
{
this (Locale.getDefault());
}
@@ -274,12 +339,21 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
* <li>3 - The long name of the time zone (daylight savings time).</li>
* <li>4 - the short name of the time zone (daylight savings time).</li>
* </ul>
+ * <p>
+ * If {@link #setZoneStrings(String[][])} has been called, then the value
+ * passed to this will be returned. Otherwise the returned array contains
+ * zone names provided by the runtime environment and any
+ * {@link java.util.spi.TimeZoneProvider} instances.
+ * </p>
*
* @return The list of time zone display strings.
+ * @see #setZoneStrings(String[][])
*/
- public String[] [] getZoneStrings ()
+ public String[][] getZoneStrings()
{
- return zoneStrings;
+ if (zoneStrings != null)
+ return zoneStrings;
+ return runtimeZoneStrings;
}
/**
@@ -537,4 +611,65 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable
^ hashCode(weekdays)
^ hashCode(zoneStrings));
}
+
+ /**
+ * Returns a {@link DateFormatSymbols} instance for the
+ * default locale obtained from either the runtime itself
+ * or one of the installed
+ * {@link java.text.spi.DateFormatSymbolsProvider} instances.
+ * This is equivalent to calling
+ * <code>getInstance(Locale.getDefault())</code>.
+ *
+ * @return a {@link DateFormatSymbols} instance for the default
+ * locale.
+ * @since 1.6
+ */
+ public static final DateFormatSymbols getInstance()
+ {
+ return getInstance(Locale.getDefault());
+ }
+
+ /**
+ * Returns a {@link DateFormatSymbols} instance for the
+ * specified locale obtained from either the runtime itself
+ * or one of the installed
+ * {@link java.text.spi.DateFormatSymbolsProvider} instances.
+ *
+ * @param locale the locale for which an instance should be
+ * returned.
+ * @return a {@link DateFormatSymbols} instance for the specified
+ * locale.
+ * @throws NullPointerException if <code>locale</code> is
+ * <code>null</code>.
+ * @since 1.6
+ */
+ public static final DateFormatSymbols getInstance(Locale locale)
+ {
+ try
+ {
+ DateFormatSymbols syms = new DateFormatSymbols(locale);
+ return syms;
+ }
+ catch (MissingResourceException e)
+ {
+ /* This means runtime support for the locale
+ * is not available, so we check providers. */
+ }
+ for (DateFormatSymbolsProvider p :
+ ServiceLoader.load(DateFormatSymbolsProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ DateFormatSymbols syms = p.getInstance(locale);
+ if (syms != null)
+ return syms;
+ break;
+ }
+ }
+ }
+ return getInstance(LocaleHelper.getFallbackLocale(locale));
+ }
+
}
diff --git a/libjava/classpath/java/text/DecimalFormat.java b/libjava/classpath/java/text/DecimalFormat.java
index 529e571331f..7febdeb49c4 100644
--- a/libjava/classpath/java/text/DecimalFormat.java
+++ b/libjava/classpath/java/text/DecimalFormat.java
@@ -439,8 +439,8 @@ public class DecimalFormat extends NumberFormat
FieldPosition pos = (FieldPosition) attributes.get(i);
Format.Field attribute = pos.getFieldAttribute();
- as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos
- .getEndIndex());
+ as.addAttribute(attribute, attribute, pos.getBeginIndex(),
+ pos.getEndIndex());
}
// return the CharacterIterator from AttributedString
@@ -659,6 +659,7 @@ public class DecimalFormat extends NumberFormat
// correct the size of the end parsing flag
int len = str.length();
if (len < stop) stop = len;
+ char groupingSeparator = symbols.getGroupingSeparator();
int i = start;
while (i < stop)
@@ -672,6 +673,7 @@ public class DecimalFormat extends NumberFormat
}
else if (this.parseIntegerOnly)
{
+ i--;
break;
}
else if (ch == decimalSeparator)
@@ -688,8 +690,19 @@ public class DecimalFormat extends NumberFormat
if (inExponent)
number.append(ch);
else
- break;
+ {
+ i--;
+ break;
+ }
}
+ else
+ {
+ if (!groupingUsed || ch != groupingSeparator)
+ {
+ i--;
+ break;
+ }
+ }
}
// 2nd special case: infinity
@@ -723,25 +736,25 @@ public class DecimalFormat extends NumberFormat
// now we have to check the suffix, done here after number parsing
// or the index will not be updated correctly...
- boolean isNegativeSuffix = str.endsWith(this.negativeSuffix);
- boolean isPositiveSuffix = str.endsWith(this.positiveSuffix);
+ boolean hasNegativeSuffix = str.endsWith(this.negativeSuffix);
+ boolean hasPositiveSuffix = str.endsWith(this.positiveSuffix);
boolean positiveEqualsNegative = negativeSuffix.equals(positiveSuffix);
positiveLen = positiveSuffix.length();
negativeLen = negativeSuffix.length();
- if (isNegative && !isNegativeSuffix)
+ if (isNegative && !hasNegativeSuffix)
{
pos.setErrorIndex(i);
return null;
}
- else if (isNegativeSuffix &&
+ else if (hasNegativeSuffix &&
!positiveEqualsNegative &&
(negativeLen > positiveLen))
{
isNegative = true;
}
- else if (!isPositiveSuffix)
+ else if (!hasPositiveSuffix)
{
pos.setErrorIndex(i);
return null;
@@ -749,7 +762,7 @@ public class DecimalFormat extends NumberFormat
if (isNegative) number.insert(0, '-');
- pos.setIndex(i - 1);
+ pos.setIndex(i);
// now we handle the return type
BigDecimal bigDecimal = new BigDecimal(number.toString());
diff --git a/libjava/classpath/java/text/DecimalFormatSymbols.java b/libjava/classpath/java/text/DecimalFormatSymbols.java
index 29d2d7ed337..f87ebbf138f 100644
--- a/libjava/classpath/java/text/DecimalFormatSymbols.java
+++ b/libjava/classpath/java/text/DecimalFormatSymbols.java
@@ -1,5 +1,5 @@
/* DecimalFormatSymbols.java -- Format symbols used by DecimalFormat
- Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2004, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,13 +38,19 @@ exception statement from your version. */
package java.text;
+import gnu.java.locale.LocaleHelper;
+
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
+
+import java.text.spi.DecimalFormatSymbolsProvider;
+
import java.util.Currency;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.ServiceLoader;
/**
* This class is a container for the symbols used by
@@ -80,6 +86,11 @@ public class DecimalFormatSymbols implements Cloneable, Serializable
/**
* This method initializes a new instance of
* <code>DecimalFormatSymbols</code> for the default locale.
+ * This constructor only obtains instances using the runtime's resources;
+ * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances,
+ * call {@link #getInstance()} instead.
+ *
+ * @see #getInstance()
*/
public DecimalFormatSymbols ()
{
@@ -137,18 +148,19 @@ public class DecimalFormatSymbols implements Cloneable, Serializable
* international currency symbol will be set to the strings "?"
* and "XXX" respectively. This generally happens with language
* locales (those with no specified country), such as
- * <code>Locale.ENGLISH</code>.
+ * <code>Locale.ENGLISH</code>. This constructor only obtains
+ * instances using the runtime's resources; to also include
+ * {@link java.text.spi.DecimalFormatSymbolsProvider} instances,
+ * call {@link #getInstance(java.util.Locale)} instead.
*
* @param loc The local to load symbols for.
* @throws NullPointerException if the locale is null.
+ * @see #getInstance(java.util.Locale)
*/
public DecimalFormatSymbols (Locale loc)
{
ResourceBundle res;
- currency = Currency.getInstance("XXX");
- currencySymbol = "?";
- intlCurrencySymbol = "XXX";
try
{
res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
@@ -158,6 +170,9 @@ public class DecimalFormatSymbols implements Cloneable, Serializable
{
res = null;
}
+ currency = Currency.getInstance("XXX");
+ currencySymbol = "?";
+ intlCurrencySymbol = "XXX";
try
{
Currency localeCurrency = Currency.getInstance(loc);
@@ -684,4 +699,68 @@ public class DecimalFormatSymbols implements Cloneable, Serializable
serialVersionOnStream = 2;
}
+
+ /**
+ * Returns a {@link DecimalFormatSymbols} instance for the
+ * default locale obtained from either the runtime itself
+ * or one of the installed
+ * {@link java.text.spi.DecimalFormatSymbolsProvider} instances.
+ * This is equivalent to calling
+ * <code>getInstance(Locale.getDefault())</code>.
+ *
+ * @return a {@link DecimalFormatSymbols} instance for the default
+ * locale.
+ * @since 1.6
+ */
+ public static final DecimalFormatSymbols getInstance()
+ {
+ return getInstance(Locale.getDefault());
+ }
+
+ /**
+ * Returns a {@link DecimalFormatSymbols} instance for the
+ * specified locale obtained from either the runtime itself
+ * or one of the installed
+ * {@link java.text.spi.DecimalFormatSymbolsProvider} instances.
+ *
+ * @param locale the locale for which an instance should be
+ * returned.
+ * @return a {@link DecimalFormatSymbols} instance for the specified
+ * locale.
+ * @throws NullPointerException if <code>locale</code> is
+ * <code>null</code>.
+ * @since 1.6
+ */
+ public static final DecimalFormatSymbols getInstance(Locale locale)
+ {
+ try
+ {
+ if (!locale.equals(Locale.ROOT))
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ locale,
+ ClassLoader.getSystemClassLoader());
+ return new DecimalFormatSymbols(locale);
+ }
+ catch (MissingResourceException x)
+ {
+ /* This means runtime support for the locale
+ * is not available, so we check providers. */
+ }
+ for (DecimalFormatSymbolsProvider p :
+ ServiceLoader.load(DecimalFormatSymbolsProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ DecimalFormatSymbols syms = p.getInstance(locale);
+ if (syms != null)
+ return syms;
+ break;
+ }
+ }
+ }
+ return getInstance(LocaleHelper.getFallbackLocale(locale));
+ }
+
}
diff --git a/libjava/classpath/java/text/MessageFormat.java b/libjava/classpath/java/text/MessageFormat.java
index 3d428ac7e51..ab71cecea5a 100644
--- a/libjava/classpath/java/text/MessageFormat.java
+++ b/libjava/classpath/java/text/MessageFormat.java
@@ -82,70 +82,72 @@ public class MessageFormat extends Format
// Recompute the locale-based formatter.
void setLocale (Locale loc)
{
- if (type == null)
- ;
- else if (type.equals("number"))
+ if (type != null)
{
- formatClass = java.lang.Number.class;
-
- if (style == null)
- format = NumberFormat.getInstance(loc);
- else if (style.equals("currency"))
- format = NumberFormat.getCurrencyInstance(loc);
- else if (style.equals("percent"))
- format = NumberFormat.getPercentInstance(loc);
- else if (style.equals("integer"))
- {
- NumberFormat nf = NumberFormat.getNumberInstance(loc);
- nf.setMaximumFractionDigits(0);
- nf.setGroupingUsed(false);
- format = nf;
- }
- else
- {
- format = NumberFormat.getNumberInstance(loc);
- DecimalFormat df = (DecimalFormat) format;
- df.applyPattern(style);
- }
- }
- else if (type.equals("time") || type.equals("date"))
- {
- formatClass = java.util.Date.class;
-
- int val = DateFormat.DEFAULT;
- boolean styleIsPattern = false;
- if (style == null)
- ;
- else if (style.equals("short"))
- val = DateFormat.SHORT;
- else if (style.equals("medium"))
- val = DateFormat.MEDIUM;
- else if (style.equals("long"))
- val = DateFormat.LONG;
- else if (style.equals("full"))
- val = DateFormat.FULL;
- else
- styleIsPattern = true;
-
- if (type.equals("time"))
- format = DateFormat.getTimeInstance(val, loc);
- else
- format = DateFormat.getDateInstance(val, loc);
-
- if (styleIsPattern)
- {
- SimpleDateFormat sdf = (SimpleDateFormat) format;
- sdf.applyPattern(style);
- }
- }
- else if (type.equals("choice"))
- {
- formatClass = java.lang.Number.class;
-
- if (style == null)
- throw new
- IllegalArgumentException ("style required for choice format");
- format = new ChoiceFormat (style);
+ if (type.equals("number"))
+ {
+ formatClass = java.lang.Number.class;
+
+ if (style == null)
+ format = NumberFormat.getInstance(loc);
+ else if (style.equals("currency"))
+ format = NumberFormat.getCurrencyInstance(loc);
+ else if (style.equals("percent"))
+ format = NumberFormat.getPercentInstance(loc);
+ else if (style.equals("integer"))
+ {
+ NumberFormat nf = NumberFormat.getNumberInstance(loc);
+ nf.setMaximumFractionDigits(0);
+ nf.setGroupingUsed(false);
+ format = nf;
+ }
+ else
+ {
+ format = NumberFormat.getNumberInstance(loc);
+ DecimalFormat df = (DecimalFormat) format;
+ df.applyPattern(style);
+ }
+ }
+ else if (type.equals("time") || type.equals("date"))
+ {
+ formatClass = java.util.Date.class;
+
+ int val = DateFormat.DEFAULT;
+ boolean styleIsPattern = false;
+ if (style != null)
+ {
+ if (style.equals("short"))
+ val = DateFormat.SHORT;
+ else if (style.equals("medium"))
+ val = DateFormat.MEDIUM;
+ else if (style.equals("long"))
+ val = DateFormat.LONG;
+ else if (style.equals("full"))
+ val = DateFormat.FULL;
+ else
+ styleIsPattern = true;
+ }
+
+ if (type.equals("time"))
+ format = DateFormat.getTimeInstance(val, loc);
+ else
+ format = DateFormat.getDateInstance(val, loc);
+
+ if (styleIsPattern)
+ {
+ SimpleDateFormat sdf = (SimpleDateFormat) format;
+ sdf.applyPattern(style);
+ }
+ }
+ else if (type.equals("choice"))
+ {
+ formatClass = java.lang.Number.class;
+
+ if (style == null)
+ throw new
+ IllegalArgumentException ("style required for choice format");
+ format = new ChoiceFormat (style);
+ }
}
}
}
diff --git a/libjava/classpath/java/text/NumberFormat.java b/libjava/classpath/java/text/NumberFormat.java
index 1bef97ffea9..4a72f443a7b 100644
--- a/libjava/classpath/java/text/NumberFormat.java
+++ b/libjava/classpath/java/text/NumberFormat.java
@@ -1,5 +1,6 @@
/* NumberFormat.java -- Formats and parses numbers
- Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,14 +39,20 @@ exception statement from your version. */
package java.text;
+import gnu.java.locale.LocaleHelper;
+
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+
+import java.text.spi.NumberFormatProvider;
+
import java.util.Currency;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.ServiceLoader;
/**
* This is the abstract superclass of all classes which format and
@@ -309,17 +316,13 @@ public abstract class NumberFormat extends Format implements Cloneable
private static NumberFormat computeInstance(Locale loc, String resource,
String def)
+ throws MissingResourceException
{
- ResourceBundle res;
- try
- {
- res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
- loc, ClassLoader.getSystemClassLoader());
- }
- catch (MissingResourceException x)
- {
- res = null;
- }
+ if (loc.equals(Locale.ROOT))
+ return new DecimalFormat(def, DecimalFormatSymbols.getInstance(loc));
+ ResourceBundle res =
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ loc, ClassLoader.getSystemClassLoader());
String fmt;
try
{
@@ -329,7 +332,7 @@ public abstract class NumberFormat extends Format implements Cloneable
{
fmt = def;
}
- DecimalFormatSymbols dfs = new DecimalFormatSymbols (loc);
+ DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(loc);
return new DecimalFormat (fmt, dfs);
}
@@ -352,11 +355,33 @@ public abstract class NumberFormat extends Format implements Cloneable
*/
public static NumberFormat getCurrencyInstance (Locale loc)
{
- NumberFormat format;
-
- format = computeInstance (loc, "currencyFormat", "\u00A4#,##0.00;(\u00A4#,##0.00)");
- format.setMaximumFractionDigits(format.getCurrency().getDefaultFractionDigits());
- return format;
+ try
+ {
+ NumberFormat format;
+
+ format = computeInstance (loc, "currencyFormat",
+ "\u00A4#,##0.00;(\u00A4#,##0.00)");
+ format.setMaximumFractionDigits(format.getCurrency().getDefaultFractionDigits());
+ return format;
+ }
+ catch (MissingResourceException e)
+ {
+ for (NumberFormatProvider p :
+ ServiceLoader.load(NumberFormatProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(loc))
+ {
+ NumberFormat nf = p.getCurrencyInstance(loc);
+ if (nf != null)
+ return nf;
+ break;
+ }
+ }
+ }
+ return getCurrencyInstance(LocaleHelper.getFallbackLocale(loc));
+ }
}
/**
@@ -456,7 +481,28 @@ public abstract class NumberFormat extends Format implements Cloneable
*/
public static NumberFormat getNumberInstance (Locale loc)
{
- return computeInstance (loc, "numberFormat", "#,##0.###");
+ try
+ {
+ return computeInstance (loc, "numberFormat", "#,##0.###");
+ }
+ catch (MissingResourceException e)
+ {
+ for (NumberFormatProvider p :
+ ServiceLoader.load(NumberFormatProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(loc))
+ {
+ NumberFormat nf = p.getNumberInstance(loc);
+ if (nf != null)
+ return nf;
+ break;
+ }
+ }
+ }
+ return getNumberInstance(LocaleHelper.getFallbackLocale(loc));
+ }
}
/**
@@ -484,10 +530,32 @@ public abstract class NumberFormat extends Format implements Cloneable
*/
public static NumberFormat getIntegerInstance(Locale locale)
{
- NumberFormat format = computeInstance (locale, "integerFormat", "#,##0");
- format.setMaximumFractionDigits(0);
- format.setParseIntegerOnly (true);
- return format;
+ try
+ {
+ NumberFormat format = computeInstance (locale,
+ "integerFormat", "#,##0");
+ format.setMaximumFractionDigits(0);
+ format.setParseIntegerOnly (true);
+ return format;
+ }
+ catch (MissingResourceException e)
+ {
+ for (NumberFormatProvider p :
+ ServiceLoader.load(NumberFormatProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(locale))
+ {
+ NumberFormat nf = p.getIntegerInstance(locale);
+ if (nf != null)
+ return nf;
+ break;
+ }
+ }
+ }
+ return getIntegerInstance(LocaleHelper.getFallbackLocale(locale));
+ }
}
/**
@@ -511,7 +579,28 @@ public abstract class NumberFormat extends Format implements Cloneable
*/
public static NumberFormat getPercentInstance (Locale loc)
{
- return computeInstance (loc, "percentFormat", "#,##0%");
+ try
+ {
+ return computeInstance (loc, "percentFormat", "#,##0%");
+ }
+ catch (MissingResourceException e)
+ {
+ for (NumberFormatProvider p :
+ ServiceLoader.load(NumberFormatProvider.class))
+ {
+ for (Locale l : p.getAvailableLocales())
+ {
+ if (l.equals(loc))
+ {
+ NumberFormat nf = p.getPercentInstance(loc);
+ if (nf != null)
+ return nf;
+ break;
+ }
+ }
+ }
+ return getPercentInstance(LocaleHelper.getFallbackLocale(loc));
+ }
}
/**
diff --git a/libjava/classpath/java/text/SimpleDateFormat.java b/libjava/classpath/java/text/SimpleDateFormat.java
index 1e195256990..f78fdcb89c5 100644
--- a/libjava/classpath/java/text/SimpleDateFormat.java
+++ b/libjava/classpath/java/text/SimpleDateFormat.java
@@ -1101,11 +1101,21 @@ public class SimpleDateFormat extends DateFormat
if (is_numeric)
{
numberFormat.setMinimumIntegerDigits(fmt_count);
- if (limit_digits)
- numberFormat.setMaximumIntegerDigits(fmt_count);
if (maybe2DigitYear)
index = pos.getIndex();
- Number n = numberFormat.parse(dateStr, pos);
+ Number n = null;
+ if (limit_digits)
+ {
+ // numberFormat.setMaximumIntegerDigits(fmt_count) may
+ // not work as expected. So we explicitly use substring
+ // of dateStr.
+ int origPos = pos.getIndex();
+ pos.setIndex(0);
+ n = numberFormat.parse(dateStr.substring(origPos, origPos + fmt_count), pos);
+ pos.setIndex(origPos + pos.getIndex());
+ }
+ else
+ n = numberFormat.parse(dateStr, pos);
if (pos == null || ! (n instanceof Long))
return null;
value = n.intValue() + offset;
diff --git a/libjava/classpath/java/text/class-dependencies.conf b/libjava/classpath/java/text/class-dependencies.conf
deleted file mode 100644
index 011b146ce10..00000000000
--- a/libjava/classpath/java/text/class-dependencies.conf
+++ /dev/null
@@ -1,220 +0,0 @@
-# This property file contains dependencies of classes, methods, and
-# field on other methods or classes.
-#
-# Syntax:
-#
-# <used>: <needed 1> [... <needed N>]
-#
-# means that when <used> is included, <needed 1> (... <needed N>) must
-# be included as well.
-#
-# <needed X> and <used> are of the form
-#
-# <class.methodOrField(signature)>
-#
-# or just
-#
-# <class>
-#
-# Within dependencies, variables can be used. A variable is defined as
-# follows:
-#
-# {variable}: value1 value2 ... value<n>
-#
-# variables can be used on the right side of dependencies as follows:
-#
-# <used>: com.bla.blu.{variable}.Class.m()V
-#
-# The use of the variable will expand to <n> dependencies of the form
-#
-# <used>: com.bla.blu.value1.Class.m()V
-# <used>: com.bla.blu.value2.Class.m()V
-# ...
-# <used>: com.bla.blu.value<n>.Class.m()V
-#
-# Variables can be redefined when building a system to select the
-# required support for features like encodings, protocols, etc.
-#
-# Hints:
-#
-# - For methods and fields, the signature is mandatory. For
-# specification, please see the Java Virtual Machine Specification by
-# SUN. Unlike in the spec, field signatures (types) are in brackets.
-#
-# - Package names must be separated by '/' (and not '.'). E.g.,
-# java/lang/Class (this is necessary, because the '.' is used to
-# separate method or field names from classes)
-#
-# - In case <needed> refers to a class, only the class itself will be
-# included in the resulting binary, NOT necessarily all its methods
-# and fields. If you want to refer to all methods and fields, you can
-# write class.* as an abbreviation.
-#
-# - Abbreviations for packages are also possible: my/package/* means all
-# methods and fields of all classes in my/package.
-#
-# - A line with a trailing '\' continues in the next line.
-
-# end of file
-
-# All locales supported are loaded via classes from java.text (see below)
-# from class gnu/java/locale/LocaleInformation_<locale_id>
-#
-# This introduces a dependency for all locales. To allow an easy selection
-# and addition of locales, the library variable {text_locales} can be set to
-# the set of supported locales.
-#
-
-{text_locales}: \
- af_ZA \
- ar_AE \
- ar_BH \
- ar_DZ \
- ar_EG \
- ar_IN \
- ar_IQ \
- ar_JO \
- ar_KW \
- ar_LB \
- ar_LY \
- ar_MA \
- ar_OM \
- ar_QA \
- ar_SD \
- ar_SY \
- ar_TN \
- ar_YE \
- be_BY \
- bn_IN \
- br_FR \
- bs_BA \
- ca_ES \
- cs_CZ \
- cy_GB \
- da_DK \
- de \
- de_AT \
- de_BE \
- de_CH \
- de_DE \
- de_LU \
- el_GR \
- en \
- en_AU \
- en_BW \
- en_CA \
- en_DK \
- en_GB \
- en_HK \
- en_IE \
- en_IN \
- en_NZ \
- en_PH \
- en_SG \
- en_US \
- en_ZA \
- en_ZW \
- es_AR \
- es_BO \
- es_CL \
- es_CO \
- es_CR \
- es_DO \
- es_EC \
- es_ES \
- es_GT \
- es_HN \
- es_MX \
- es_NI \
- es_PA \
- es_PE \
- es_PR \
- es_PY \
- es_SV \
- es_US \
- es_UY \
- es_VE \
- et_EE \
- eu_ES \
- fa_IR \
- fi_FI \
- fo_FO \
- fr_BE \
- fr_CA \
- fr_CH \
- fr_FR \
- fr_LU \
- ga_IE \
- gd_GB \
- gl_ES \
- gv_GB \
- he_IL \
- hi_IN \
- hr_HR \
- hu_HU \
- id_ID \
- it_CH \
- it_IT \
- iw_IL \
- ja_JP \
- ka_GE \
- kl_GL \
- ko_KR \
- kw_GB \
- lt_LT \
- lv_LV \
- mi_NZ \
- mk_MK \
- mr_IN \
- mt_MT \
- nl \
- nl_BE \
- nl_NL \
- nn_NO \
- no_NO \
- oc_FR \
- pl_PL \
- pt_BR \
- pt_PT \
- ro_RO \
- ru_RU \
- ru_UA \
- se_NO \
- sk_SK \
- sl_SI \
- sq_AL \
- sr_YU \
- sv_FI \
- sv_SE \
- ta_IN \
- te_IN \
- tg_TJ \
- tl_PH \
- tr_TR \
- uk_UA \
- ur_PK \
- uz_UZ \
- vi_VN \
- yi_US \
- zh_CN \
- zh_HK \
- zh_SG \
- zh_TW
-
-java/text/Collator.getInstance(Ljava/util/Locale;)Ljava/text/Collator;: \
- gnu/java/locale/LocaleInformation_{text_locales}.*
-
-java/text/DateFormatSymbols.<init>(Ljava/util/Locale;)V: \
- gnu/java/locale/LocaleInformation_{text_locales}.*
-
-java/text/DecimalFormatSymbols.<init>(Ljava/util/Locale;)V: \
- gnu/java/locale/LocaleInformation_{text_locales}.*
-
-java/text/BreakIterator.getInstance(Ljava/lang/String;Ljava/util/Locale;)Ljava/text/BreakIterator;: \
- gnu/java/locale/LocaleInformation_{text_locales}.*
-
-java/text/NumberFormat.computeInstance(Ljava/util/Locale;Ljava/lang/String;Ljava/lang/String;)Ljava/text/NumberFormat;: \
- gnu/java/locale/LocaleInformation_{text_locales}.*
-
-java/text/DateFormat.computeInstance(IILjava/util/Locale;ZZ)Ljava/text/DateFormat;: \
- gnu/java/locale/LocaleInformation_{text_locales}.*
diff --git a/libjava/classpath/java/text/spi/BreakIteratorProvider.java b/libjava/classpath/java/text/spi/BreakIteratorProvider.java
new file mode 100644
index 00000000000..7e5e056b819
--- /dev/null
+++ b/libjava/classpath/java/text/spi/BreakIteratorProvider.java
@@ -0,0 +1,124 @@
+/* BreakIteratorProvider.java -- Providers of localized instances
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.text.spi;
+
+import java.text.BreakIterator;
+
+import java.util.Locale;
+
+import java.util.spi.LocaleServiceProvider;
+
+/**
+ * A {@link BreakIteratorProvider} provides localized
+ * instances of {@link java.text.BreakIterator}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class BreakIteratorProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link BreakIteratorProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected BreakIteratorProvider()
+ {
+ }
+
+ /**
+ * Returns a {@link java.text.BreakIterator} instance
+ * for character breaks in the specified
+ * {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance for character breaks.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.BreakIterator#getCharacterInstance(java.util.Locale)
+ */
+ public abstract BreakIterator getCharacterInstance(Locale locale);
+
+ /**
+ * Returns a {@link java.text.BreakIterator} instance
+ * for line breaks in the specified {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance for line breaks.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.BreakIterator#getLineInstance(java.util.Locale)
+ */
+ public abstract BreakIterator getLineInstance(Locale locale);
+
+ /**
+ * Returns a {@link java.text.BreakIterator} instance
+ * for sentence breaks in the specified
+ * {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance for sentence breaks.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.BreakIterator#getSentenceInstance(java.util.Locale)
+ */
+ public abstract BreakIterator getSentenceInstance(Locale locale);
+
+ /**
+ * Returns a {@link java.text.BreakIterator} instance
+ * for word breaks in the specified
+ * {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance for word breaks.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.BreakIterator#getWordInstance(java.util.Locale)
+ */
+ public abstract BreakIterator getWordInstance(Locale locale);
+
+}
diff --git a/libjava/classpath/java/text/spi/CollatorProvider.java b/libjava/classpath/java/text/spi/CollatorProvider.java
new file mode 100644
index 00000000000..6d6f409397b
--- /dev/null
+++ b/libjava/classpath/java/text/spi/CollatorProvider.java
@@ -0,0 +1,79 @@
+/* CollatorProvider.java -- Providers of localized instances
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.text.spi;
+
+import java.text.Collator;
+
+import java.util.Locale;
+
+import java.util.spi.LocaleServiceProvider;
+
+/**
+ * A {@link CollatorProvider} provides localized
+ * instances of {@link java.text.Collator}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class CollatorProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link CollatorProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected CollatorProvider()
+ {
+ }
+
+ /**
+ * Returns a {@link java.text.Collator} instance
+ * for the specified {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.Collator#getInstance(java.util.Locale)
+ */
+ public abstract Collator getInstance(Locale locale);
+
+}
diff --git a/libjava/classpath/java/text/spi/DateFormatProvider.java b/libjava/classpath/java/text/spi/DateFormatProvider.java
new file mode 100644
index 00000000000..43d54a0c60d
--- /dev/null
+++ b/libjava/classpath/java/text/spi/DateFormatProvider.java
@@ -0,0 +1,129 @@
+/* DateFormatProvider.java -- Providers of localized instances
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.text.spi;
+
+import java.text.DateFormat;
+
+import java.util.Locale;
+
+import java.util.spi.LocaleServiceProvider;
+
+/**
+ * A {@link DateFormatProvider} provides localized
+ * instances of {@link java.text.DateFormat}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class DateFormatProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link DateFormatProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected DateFormatProvider()
+ {
+ }
+
+ /**
+ * Returns a {@link java.text.DateFormat} instance
+ * for formatting dates with the given style in the specified
+ * {@link java.util.Locale}.
+ *
+ * @param style the formatting style; one of {@link DateFormat#SHORT},
+ * {@link DateFormat#MEDIUM}, {@link DateFormat#LONG}
+ * or {@link DateFormat#FULL}.
+ * @param locale the desired locale.
+ * @return the localized instance for formatting dates.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the style is invalid or
+ * the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.DateFormat#getDateInstance(int,java.util.Locale)
+ */
+ public abstract DateFormat getDateInstance(int style,
+ Locale locale);
+
+ /**
+ * Returns a {@link java.text.DateFormat} instance
+ * for formatting dates and times with the given style in the
+ * specified {@link java.util.Locale}.
+ *
+ * @param dateStyle the date formatting style; one of
+ * {@link DateFormat#SHORT}, {@link DateFormat#MEDIUM},
+ * {@link DateFormat#LONG} or {@link DateFormat#FULL}.
+ * @param timeStyle the time formatting style; one of
+ * {@link DateFormat#SHORT}, {@link DateFormat#MEDIUM},
+ * {@link DateFormat#LONG} or {@link DateFormat#FULL}.
+ * @param locale the desired locale.
+ * @return the localized instance for formatting dates.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if either style is invalid or
+ * the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.DateFormat#getDateInstance(java.util.Locale)
+ */
+ public abstract DateFormat getDateTimeInstance(int dateStyle,
+ int timeStyle,
+ Locale locale);
+
+ /**
+ * Returns a {@link java.text.DateFormat} instance
+ * for formatting times with the given style in the specified
+ * {@link java.util.Locale}.
+ *
+ * @param style the formatting style; one of {@link DateFormat#SHORT},
+ * {@link DateFormat#MEDIUM}, {@link DateFormat#LONG}
+ * or {@link DateFormat#FULL}.
+ * @param locale the desired locale.
+ * @return the localized instance for formatting times.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the style is invalid or
+ * the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.DateFormat#getTimeInstance(int,java.util.Locale)
+ */
+ public abstract DateFormat getTimeInstance(int style,
+ Locale locale);
+
+}
diff --git a/libjava/classpath/java/text/spi/DateFormatSymbolsProvider.java b/libjava/classpath/java/text/spi/DateFormatSymbolsProvider.java
new file mode 100644
index 00000000000..a0e97595fbe
--- /dev/null
+++ b/libjava/classpath/java/text/spi/DateFormatSymbolsProvider.java
@@ -0,0 +1,79 @@
+/* DateFormatSymbolsProvider.java -- Providers of localized instances
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.text.spi;
+
+import java.text.DateFormatSymbols;
+
+import java.util.Locale;
+
+import java.util.spi.LocaleServiceProvider;
+
+/**
+ * A {@link DateFormatSymbolsProvider} provides localized
+ * instances of {@link java.text.DateFormatSymbols}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class DateFormatSymbolsProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link DateFormatSymbolsProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected DateFormatSymbolsProvider()
+ {
+ }
+
+ /**
+ * Returns a {@link java.text.DateFormatSymbols} instance
+ * for the specified {@link java.util.Locale}.
+ *
+ * @param locale the locale to express the symbols in.
+ * @return the localized instance.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.DateFormatSymbols#getInstance(java.util.Locale)
+ */
+ public abstract DateFormatSymbols getInstance(Locale locale);
+
+}
diff --git a/libjava/classpath/java/text/spi/DecimalFormatSymbolsProvider.java b/libjava/classpath/java/text/spi/DecimalFormatSymbolsProvider.java
new file mode 100644
index 00000000000..d772b1eee4f
--- /dev/null
+++ b/libjava/classpath/java/text/spi/DecimalFormatSymbolsProvider.java
@@ -0,0 +1,79 @@
+/* DecimalFormatSymbolsProvider.java -- Providers of localized instances
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.text.spi;
+
+import java.text.DecimalFormatSymbols;
+
+import java.util.Locale;
+
+import java.util.spi.LocaleServiceProvider;
+
+/**
+ * A {@link DecimalFormatSymbolsProvider} provides localized
+ * instances of {@link java.text.DecimalFormatSymbols}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class DecimalFormatSymbolsProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link DecimalFormatSymbolsProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected DecimalFormatSymbolsProvider()
+ {
+ }
+
+ /**
+ * Returns a {@link java.text.DecimalFormatSymbols} instance
+ * for the specified {@link java.util.Locale}.
+ *
+ * @param locale the locale to express the symbols in.
+ * @return the localized instance.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.DecimalFormatSymbols#getInstance(java.util.Locale)
+ */
+ public abstract DecimalFormatSymbols getInstance(Locale locale);
+
+}
diff --git a/libjava/classpath/java/text/spi/NumberFormatProvider.java b/libjava/classpath/java/text/spi/NumberFormatProvider.java
new file mode 100644
index 00000000000..2a252701f4a
--- /dev/null
+++ b/libjava/classpath/java/text/spi/NumberFormatProvider.java
@@ -0,0 +1,129 @@
+/* NumberFormatProvider.java -- Providers of localized instances
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.text.spi;
+
+import java.text.NumberFormat;
+
+import java.util.Locale;
+
+import java.util.spi.LocaleServiceProvider;
+
+/**
+ * A {@link NumberFormatProvider} provides localized
+ * instances of {@link java.text.NumberFormat}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class NumberFormatProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link NumberFormatProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected NumberFormatProvider()
+ {
+ }
+
+ /**
+ * Returns a {@link java.text.NumberFormat} instance
+ * for monetary values in the specified
+ * {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance for monetary values.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.NumberFormat#getCurrencyInstance(java.util.Locale)
+ */
+ public abstract NumberFormat getCurrencyInstance(Locale locale);
+
+ /**
+ * Returns a {@link java.text.NumberFormat} instance
+ * for integers in the specified {@link java.util.Locale}.
+ * The returned instance should be configured to round
+ * floating point numbers to the nearest integer using
+ * {@link java.math.RoundingMode#HALF_EVEN} rounding,
+ * and to parse only the integer part of a number.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance for integers.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.NumberFormat#getIntegerInstance(java.util.Locale)
+ * @see java.math.RoundingMode#HALF_EVEN
+ * @see java.text.NumberFormat#isParseIntegerOnly()
+ */
+ public abstract NumberFormat getIntegerInstance(Locale locale);
+
+ /**
+ * Returns a general-purpose {@link java.text.NumberFormat}
+ * instance in the specified {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return a general-purpose localized instance.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.NumberFormat#getNumberInstance(java.util.Locale)
+ */
+ public abstract NumberFormat getNumberInstance(Locale locale);
+
+ /**
+ * Returns a {@link java.text.NumberFormat} instance
+ * for percentage values in the specified
+ * {@link java.util.Locale}.
+ *
+ * @param locale the desired locale.
+ * @return the localized instance for percentage values.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.text.NumberFormat#getPercentInstance(java.util.Locale)
+ */
+ public abstract NumberFormat getPercentInstance(Locale locale);
+
+}
diff --git a/libjava/classpath/java/text/spi/package.html b/libjava/classpath/java/text/spi/package.html
new file mode 100644
index 00000000000..7f5232ce09c
--- /dev/null
+++ b/libjava/classpath/java/text/spi/package.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in java.text.spi package.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - java.text.spi</title></head>
+
+<body>
+
+<p>
+A series of service provider interfaces for use by the
+classes in <code>java.text</code>.
+</p>
+<p><span style="font-weight: bold;">Since</span>: 1.6</p>
+</body>
+</html>
diff --git a/libjava/classpath/java/util/AbstractMap.java b/libjava/classpath/java/util/AbstractMap.java
index 29249e1dc22..2f58121cede 100644
--- a/libjava/classpath/java/util/AbstractMap.java
+++ b/libjava/classpath/java/util/AbstractMap.java
@@ -69,10 +69,23 @@ import java.io.Serializable;
*/
public abstract class AbstractMap<K, V> implements Map<K, V>
{
- /** @since 1.6 */
+ /**
+ * A class containing an immutable key and value. The
+ * implementation of {@link Entry#setValue(V)} for this class
+ * simply throws an {@link UnsupportedOperationException},
+ * thus preventing changes being made. This is useful when
+ * a static thread-safe view of a map is required.
+ *
+ * @since 1.6
+ */
public static class SimpleImmutableEntry<K, V>
implements Entry<K, V>, Serializable
{
+ /**
+ * Compatible with JDK 1.6
+ */
+ private static final long serialVersionUID = 7138329143949025153L;
+
K key;
V value;
@@ -670,6 +683,12 @@ public abstract class AbstractMap<K, V> implements Map<K, V>
*/
public static class SimpleEntry<K, V> implements Entry<K, V>, Serializable
{
+
+ /**
+ * Compatible with JDK 1.6
+ */
+ private static final long serialVersionUID = -8499721149061103585L;
+
/**
* The key. Package visible for direct manipulation.
*/
@@ -730,7 +749,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V>
*
* @return the key
*/
- public final K getKey()
+ public K getKey()
{
return key;
}
@@ -741,7 +760,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V>
*
* @return the value
*/
- public final V getValue()
+ public V getValue()
{
return value;
}
@@ -755,7 +774,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V>
*
* @return the hash code
*/
- public final int hashCode()
+ public int hashCode()
{
return (AbstractMap.hashCode(key) ^ AbstractMap.hashCode(value));
}
@@ -788,7 +807,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V>
*
* @return the string representation
*/
- public final String toString()
+ public String toString()
{
return key + "=" + value;
}
diff --git a/libjava/classpath/java/util/Arrays.java b/libjava/classpath/java/util/Arrays.java
index 41e80455104..9443ced5bdd 100644
--- a/libjava/classpath/java/util/Arrays.java
+++ b/libjava/classpath/java/util/Arrays.java
@@ -92,8 +92,38 @@ public class Arrays
*/
public static int binarySearch(byte[] a, byte key)
{
- int low = 0;
- int hi = a.length - 1;
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key);
+ }
+
+ /**
+ * Perform a binary search of a range of a byte array for a key. The range
+ * must be sorted (as by the <code>sort(byte[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static int binarySearch(byte[] a, int low, int hi, byte key)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
int mid = 0;
while (low <= hi)
{
@@ -126,8 +156,38 @@ public class Arrays
*/
public static int binarySearch(char[] a, char key)
{
- int low = 0;
- int hi = a.length - 1;
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key);
+ }
+
+ /**
+ * Perform a binary search of a range of a char array for a key. The range
+ * must be sorted (as by the <code>sort(char[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static int binarySearch(char[] a, int low, int hi, char key)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
int mid = 0;
while (low <= hi)
{
@@ -160,8 +220,38 @@ public class Arrays
*/
public static int binarySearch(short[] a, short key)
{
- int low = 0;
- int hi = a.length - 1;
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key);
+ }
+
+ /**
+ * Perform a binary search of a range of a short array for a key. The range
+ * must be sorted (as by the <code>sort(short[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static int binarySearch(short[] a, int low, int hi, short key)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
int mid = 0;
while (low <= hi)
{
@@ -194,8 +284,38 @@ public class Arrays
*/
public static int binarySearch(int[] a, int key)
{
- int low = 0;
- int hi = a.length - 1;
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key);
+ }
+
+ /**
+ * Perform a binary search of a range of an integer array for a key. The range
+ * must be sorted (as by the <code>sort(int[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static int binarySearch(int[] a, int low, int hi, int key)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
int mid = 0;
while (low <= hi)
{
@@ -228,8 +348,38 @@ public class Arrays
*/
public static int binarySearch(long[] a, long key)
{
- int low = 0;
- int hi = a.length - 1;
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key);
+ }
+
+ /**
+ * Perform a binary search of a range of a long array for a key. The range
+ * must be sorted (as by the <code>sort(long[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static int binarySearch(long[] a, int low, int hi, long key)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
int mid = 0;
while (low <= hi)
{
@@ -262,9 +412,39 @@ public class Arrays
*/
public static int binarySearch(float[] a, float key)
{
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key);
+ }
+
+ /**
+ * Perform a binary search of a range of a float array for a key. The range
+ * must be sorted (as by the <code>sort(float[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static int binarySearch(float[] a, int low, int hi, float key)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
// Must use Float.compare to take into account NaN, +-0.
- int low = 0;
- int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
@@ -297,9 +477,39 @@ public class Arrays
*/
public static int binarySearch(double[] a, double key)
{
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key);
+ }
+
+ /**
+ * Perform a binary search of a range of a double array for a key. The range
+ * must be sorted (as by the <code>sort(double[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static int binarySearch(double[] a, int low, int hi, double key)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
// Must use Double.compare to take into account NaN, +-0.
- int low = 0;
- int hi = a.length - 1;
int mid = 0;
while (low <= hi)
{
@@ -337,10 +547,33 @@ public class Arrays
*/
public static int binarySearch(Object[] a, Object key)
{
+ if (a.length == 0)
+ return -1;
return binarySearch(a, key, null);
}
/**
+ * Perform a binary search of a range of an Object array for a key. The range
+ * must be sorted (as by the <code>sort(Object[], int, int)</code> method) -
+ * if it is not, the behaviour of this method is undefined, and may be an
+ * infinite loop. If the array contains the key more than once, any one of
+ * them may be found. Note: although the specification allows for an infinite
+ * loop if the array is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ */
+ public static int binarySearch(Object[] a, int low, int hi, Object key)
+ {
+ return binarySearch(a, low, hi, key, null);
+ }
+
+ /**
* Perform a binary search of an Object array for a key, using a supplied
* Comparator. The array must be sorted (as by the sort() method with the
* same Comparator) - if it is not, the behaviour of this method is
@@ -364,8 +597,44 @@ public class Arrays
*/
public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c)
{
- int low = 0;
- int hi = a.length - 1;
+ if (a.length == 0)
+ return -1;
+ return binarySearch(a, 0, a.length - 1, key, c);
+ }
+
+ /**
+ * Perform a binary search of a range of an Object array for a key using
+ * a {@link Comparator}. The range must be sorted (as by the
+ * <code>sort(Object[], int, int)</code> method) - if it is not, the
+ * behaviour of this method is undefined, and may be an infinite loop. If
+ * the array contains the key more than once, any one of them may be found.
+ * Note: although the specification allows for an infinite loop if the array
+ * is unsorted, it will not happen in this implementation.
+ *
+ * @param a the array to search (must be sorted)
+ * @param low the lowest index to search from.
+ * @param hi the highest index to search to.
+ * @param key the value to search for
+ * @param c the comparator by which the array is sorted; or null to
+ * use the elements' natural order
+ * @return the index at which the key was found, or -n-1 if it was not
+ * found, where n is the index of the first value higher than key or
+ * a.length if there is no such value.
+ * @throws ClassCastException if key could not be compared with one of the
+ * elements of a
+ * @throws IllegalArgumentException if <code>low > hi</code>
+ * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or
+ * <code>hi > a.length</code>.
+ */
+ public static <T> int binarySearch(T[] a, int low, int hi, T key,
+ Comparator<? super T> c)
+ {
+ if (low > hi)
+ throw new IllegalArgumentException("The start index is higher than " +
+ "the finish index.");
+ if (low < 0 || hi > a.length)
+ throw new ArrayIndexOutOfBoundsException("One of the indices is out " +
+ "of bounds.");
int mid = 0;
while (low <= hi)
{
@@ -3062,4 +3331,701 @@ public class Arrays
return array;
}
}
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>false</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>false</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>false</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(boolean[],int,int)
+ */
+ public static boolean[] copyOf(boolean[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>false</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>false</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(boolean[],int)
+ */
+ public static boolean[] copyOfRange(boolean[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ boolean[] newArray = new boolean[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, false);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>(byte)0</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>(byte)0</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>(byte)0</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(byte[],int,int)
+ */
+ public static byte[] copyOf(byte[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>(byte)0</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>(byte)0</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(byte[],int)
+ */
+ public static byte[] copyOfRange(byte[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ byte[] newArray = new byte[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, (byte)0);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>'\0'</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>'\0'</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>'\0'</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(char[],int,int)
+ */
+ public static char[] copyOf(char[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>'\0'</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>'\0'</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(char[],int)
+ */
+ public static char[] copyOfRange(char[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ char[] newArray = new char[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, '\0');
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>0d</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>0d</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>0d</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(double[],int,int)
+ */
+ public static double[] copyOf(double[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>0d</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>0d</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(double[],int)
+ */
+ public static double[] copyOfRange(double[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ double[] newArray = new double[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, 0d);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>0f</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>0f</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>0f</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(float[],int,int)
+ */
+ public static float[] copyOf(float[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>0f</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>0f</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(float[],int)
+ */
+ public static float[] copyOfRange(float[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ float[] newArray = new float[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, 0f);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>0</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>0</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>0</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(int[],int,int)
+ */
+ public static int[] copyOf(int[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>0</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>0</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(int[],int)
+ */
+ public static int[] copyOfRange(int[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ int[] newArray = new int[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, 0);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>0L</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>0L</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>0L</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(long[],int,int)
+ */
+ public static long[] copyOf(long[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>0L</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>0L</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(long[],int)
+ */
+ public static long[] copyOfRange(long[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ long[] newArray = new long[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, 0L);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>(short)0</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>(short)0</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>(short)0</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(short[],int,int)
+ */
+ public static short[] copyOf(short[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>(short)0</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>(short)0</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(short[],int)
+ */
+ public static short[] copyOfRange(short[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ short[] newArray = new short[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, (short)0);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>null</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>null</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength)</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>null</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(T[],int,int)
+ */
+ public static <T> T[] copyOf(T[] original, int newLength)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>null</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>null</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(T[],int)
+ */
+ public static <T> T[] copyOfRange(T[] original, int from, int to)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ T[] newArray = (T[]) new Object[to - from];
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, null);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
+
+ /**
+ * Returns a copy of the supplied array, truncating or padding as
+ * necessary with <code>null</code> to obtain the specified length.
+ * Indices that are valid for both arrays will return the same value.
+ * Indices that only exist in the returned array (due to the new length
+ * being greater than the original length) will return <code>null</code>.
+ * This is equivalent to calling
+ * <code>copyOfRange(original, 0, newLength, newType)</code>. The returned
+ * array will be of the specified type, <code>newType</code>.
+ *
+ * @param original the original array to be copied.
+ * @param newLength the length of the returned array.
+ * @param newType the type of the returned array.
+ * @return a copy of the original array, truncated or padded with
+ * <code>null</code> to obtain the required length.
+ * @throws NegativeArraySizeException if <code>newLength</code> is negative.
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOfRange(U[],int,int,Class)
+ */
+ public static <T,U> T[] copyOf(U[] original, int newLength,
+ Class<? extends T[]> newType)
+ {
+ if (newLength < 0)
+ throw new NegativeArraySizeException("The array size is negative.");
+ return copyOfRange(original, 0, newLength, newType);
+ }
+
+ /**
+ * Copies the specified range of the supplied array to a new
+ * array, padding as necessary with <code>null</code>
+ * if <code>to</code> is greater than the length of the original
+ * array. <code>from</code> must be in the range zero to
+ * <code>original.length</code> and can not be greater than
+ * <code>to</code>. The initial element of the
+ * returned array will be equal to <code>original[from]</code>,
+ * except where <code>from</code> is equal to <code>to</code>
+ * (where a zero-length array will be returned) or <code>
+ * <code>from</code> is equal to <code>original.length</code>
+ * (where an array padded with <code>null</code> will be
+ * returned). The returned array is always of length
+ * <code>to - from</code> and will be of the specified type,
+ * <code>newType</code>.
+ *
+ * @param original the array from which to copy.
+ * @param from the initial index of the range, inclusive.
+ * @param to the final index of the range, exclusive.
+ * @param newType the type of the returned array.
+ * @return a copy of the specified range, with padding to
+ * obtain the required length.
+ * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code>
+ * or <code>from > original.length</code>
+ * @throws IllegalArgumentException if <code>from > to</code>
+ * @throws NullPointerException if <code>original</code> is <code>null</code>.
+ * @since 1.6
+ * @see #copyOf(T[],int)
+ */
+ public static <T,U> T[] copyOfRange(U[] original, int from, int to,
+ Class<? extends T[]> newType)
+ {
+ if (from > to)
+ throw new IllegalArgumentException("The initial index is after " +
+ "the final index.");
+ T[] newArray = (T[]) Array.newInstance(newType.getComponentType(),
+ to - from);
+ if (to > original.length)
+ {
+ System.arraycopy(original, from, newArray, 0,
+ original.length - from);
+ fill(newArray, original.length, newArray.length, null);
+ }
+ else
+ System.arraycopy(original, from, newArray, 0, to - from);
+ return newArray;
+ }
}
diff --git a/libjava/classpath/java/util/Calendar.java b/libjava/classpath/java/util/Calendar.java
index 8c46c01936c..2b385b1a0b2 100644
--- a/libjava/classpath/java/util/Calendar.java
+++ b/libjava/classpath/java/util/Calendar.java
@@ -43,9 +43,12 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.text.DateFormatSymbols;
+
/**
* This class is an abstract base class for Calendars, which can be
* used to convert between <code>Date</code> objects and a set of
@@ -99,6 +102,20 @@ day_of_week + week_of_year</pre>
* specific field by one, propagating overflows), or
* <code>add</code>ing/substracting a fixed amount to a field.
*
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Jochen Hoenicke (Jochen.Hoenicke@Informatik.Uni-Oldenburg.de)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @author Jeff Sturm (jsturm@one-point.com)
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Bryce McKinlay (mckinlay@redhat.com)
+ * @author Ingo Proetel (proetel@aicas.com)
+ * @author Jerry Quinn (jlquinn@optonline.net)
+ * @author Jeroen Frijters (jeroen@frijters.net)
+ * @author Noa Resare (noa@resare.com)
+ * @author Sven de Marothy (sven@physto.se)
+ * @author David Gilbert (david.gilbert@object-refinery.com)
+ * @author Olivier Jolly (olivier.jolly@pcedev.com)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
* @see Date
* @see GregorianCalendar
* @see TimeZone
@@ -326,6 +343,34 @@ public abstract class Calendar
public static final int PM = 1;
/**
+ * A style specifier for {@link #getDisplayNames(int,int,Locale)}
+ * stating that names should be returned in both long and short variants.
+ *
+ * @since 1.6
+ * @see #SHORT
+ * @see #LONG
+ */
+ public static final int ALL_STYLES = 0;
+
+ /**
+ * A style specifier for {@link #getDisplayName(int,int,Locale)}
+ * and {@link #getDisplayNames(int,int,Locale)} stating that names
+ * should be returned in their short variant if applicable.
+ *
+ * @since 1.6
+ */
+ public static final int SHORT = 1;
+
+ /**
+ * A style specifier for {@link #getDisplayName(int,int,Locale)}
+ * and {@link #getDisplayNames(int,int,Locale)} stating that names
+ * should be returned in their long variant if applicable.
+ *
+ * @since 1.6
+ */
+ public static final int LONG = 2;
+
+ /**
* The time fields. The array is indexed by the constants YEAR to
* DST_OFFSET.
* @serial
@@ -527,7 +572,7 @@ public abstract class Calendar
* Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle
* lookup for every getInstance call.
*/
- private static HashMap cache = new HashMap();
+ private static HashMap<Locale,Class> cache = new HashMap<Locale,Class>();
/** Preset argument types for calendar-class constructor lookup. */
private static Class[] ctorArgTypes = new Class[]
@@ -549,7 +594,7 @@ public abstract class Calendar
*/
public static synchronized Calendar getInstance(TimeZone zone, Locale locale)
{
- Class calendarClass = (Class) cache.get(locale);
+ Class calendarClass = cache.get(locale);
Throwable exception = null;
try
@@ -1343,4 +1388,205 @@ public abstract class Calendar
areFieldsSet = false;
}
}
+
+ /**
+ * Returns a localised textual representation of the current value
+ * of the given field using the specified style. If there is no
+ * applicable textual representation (e.g. the field has a numeric
+ * value), then <code>null</code> is returned. If one does exist,
+ * then the value is obtained from {@link #get(int)} and converted
+ * appropriately. For example, if the <code>MONTH</code> field is
+ * requested, then <code>get(MONTH)</code> is called. This is then
+ * converted to a textual representation based on its value and
+ * the style requested; if the <code>LONG</code> style is requested
+ * and the returned value is <code>11</code> from a
+ * {@link GregorianCalendar} implementation, then <code>"December"</code>
+ * is returned. By default, a textual representation is available
+ * for all fields which have an applicable value obtainable from
+ * {@link java.text.DateFormatSymbols}.
+ *
+ * @param field the calendar field whose textual representation should
+ * be obtained.
+ * @param style the style to use; either {@link #LONG} or {@link #SHORT}.
+ * @param locale the locale to use for translation.
+ * @return the textual representation of the given field in the specified
+ * style, or <code>null</code> if none is applicable.
+ * @throws IllegalArgumentException if <code>field</code> or <code>style</code>
+ * or invalid, or the calendar is non-lenient
+ * and has invalid values.
+ * @throws NullPointerException if <code>locale</code> is <code>null</code>.
+ * @since 1.6
+ */
+ public String getDisplayName(int field, int style, Locale locale)
+ {
+ if (field < 0 || field >= FIELD_COUNT)
+ throw new IllegalArgumentException("The field value, " + field +
+ ", is invalid.");
+ if (style != SHORT && style != LONG)
+ throw new IllegalArgumentException("The style must be either " +
+ "short or long.");
+ if (field == YEAR || field == WEEK_OF_YEAR ||
+ field == WEEK_OF_MONTH || field == DAY_OF_MONTH ||
+ field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH ||
+ field == HOUR || field == HOUR_OF_DAY || field == MINUTE ||
+ field == SECOND || field == MILLISECOND)
+ return null;
+
+ int value = get(field);
+ DateFormatSymbols syms = DateFormatSymbols.getInstance(locale);
+ if (field == ERA)
+ return syms.getEras()[value];
+ if (field == MONTH)
+ if (style == LONG)
+ return syms.getMonths()[value];
+ else
+ return syms.getShortMonths()[value];
+ if (field == DAY_OF_WEEK)
+ if (style == LONG)
+ return syms.getWeekdays()[value];
+ else
+ return syms.getShortWeekdays()[value];
+ if (field == AM_PM)
+ return syms.getAmPmStrings()[value];
+ if (field == ZONE_OFFSET)
+ if (style == LONG)
+ return syms.getZoneStrings()[value][1];
+ else
+ return syms.getZoneStrings()[value][2];
+ if (field == DST_OFFSET)
+ if (style == LONG)
+ return syms.getZoneStrings()[value][3];
+ else
+ return syms.getZoneStrings()[value][4];
+
+ throw new InternalError("Failed to resolve field " + field +
+ " with style " + style + " for locale " +
+ locale);
+ }
+
+ /**
+ * Returns a map linking all specified textual representations
+ * of the given field to their numerical values. The textual
+ * representations included are determined by the specified
+ * style and locale. For example, if the style <code>LONG</code>
+ * is specified and the German locale, then the map will
+ * contain "Montag" to {@link #MONDAY}, "Dienstag" to
+ * {@link #TUESDAY}, "Mittwoch" to {@link #WEDNESDAY} and
+ * so on. The default implementation uses the values returned
+ * by {@link DateFormatSymbols} so, for example, the style
+ * {@link #ALL_STYLES} and the field {@link #MONTH} will return
+ * a map filled with the values returned from
+ * {@link DateFormatSymbols#getMonths()} and
+ * {@link DateFormatSymbols#getShortMonths()}. If there are
+ * no textual representations for a given field (usually because
+ * it is purely numeric, such as the year in the
+ * {@link GregorianCalendar}), <code>null</code> is returned.
+ *
+ * @param field the calendar field whose textual representation should
+ * be obtained.
+ * @param style the style to use; either {@link #LONG}, {@link #SHORT}
+ * or {@link ALL_STYLES}.
+ * @param locale the locale to use for translation.
+ * @return a map of the textual representations of the given field in the
+ * specified style to their numeric values, or <code>null</code>
+ * if none is applicable.
+ * @throws IllegalArgumentException if <code>field</code> or <code>style</code>
+ * or invalid, or the calendar is non-lenient
+ * and has invalid values.
+ * @throws NullPointerException if <code>locale</code> is <code>null</code>.
+ * @since 1.6
+ */
+ public Map<String,Integer> getDisplayNames(int field, int style, Locale locale)
+ {
+ if (field < 0 || field >= FIELD_COUNT)
+ throw new IllegalArgumentException("The field value, " + field +
+ ", is invalid.");
+ if (style != SHORT && style != LONG && style != ALL_STYLES)
+ throw new IllegalArgumentException("The style must be either " +
+ "short, long or all styles.");
+ if (field == YEAR || field == WEEK_OF_YEAR ||
+ field == WEEK_OF_MONTH || field == DAY_OF_MONTH ||
+ field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH ||
+ field == HOUR || field == HOUR_OF_DAY || field == MINUTE ||
+ field == SECOND || field == MILLISECOND)
+ return null;
+
+ DateFormatSymbols syms = DateFormatSymbols.getInstance(locale);
+ Map<String,Integer> map = new HashMap<String,Integer>();
+ if (field == ERA)
+ {
+ String[] eras = syms.getEras();
+ for (int a = 0; a < eras.length; ++a)
+ map.put(eras[a], a);
+ return map;
+ }
+ if (field == MONTH)
+ {
+ if (style == LONG || style == ALL_STYLES)
+ {
+ String[] months = syms.getMonths();
+ for (int a = 0; a < months.length; ++a)
+ map.put(months[a], a);
+ }
+ if (style == SHORT || style == ALL_STYLES)
+ {
+ String[] months = syms.getShortMonths();
+ for (int a = 0; a < months.length; ++a)
+ map.put(months[a], a);
+ }
+ return map;
+ }
+ if (field == DAY_OF_WEEK)
+ {
+ if (style == LONG || style == ALL_STYLES)
+ {
+ String[] weekdays = syms.getWeekdays();
+ for (int a = SUNDAY; a < weekdays.length; ++a)
+ map.put(weekdays[a], a);
+ }
+ if (style == SHORT || style == ALL_STYLES)
+ {
+ String[] weekdays = syms.getShortWeekdays();
+ for (int a = SUNDAY; a < weekdays.length; ++a)
+ map.put(weekdays[a], a);
+ }
+ return map;
+ }
+ if (field == AM_PM)
+ {
+ String[] ampms = syms.getAmPmStrings();
+ for (int a = 0; a < ampms.length; ++a)
+ map.put(ampms[a], a);
+ return map;
+ }
+ if (field == ZONE_OFFSET)
+ {
+ String[][] zones = syms.getZoneStrings();
+ for (int a = 0; a < zones.length; ++a)
+ {
+ if (style == LONG || style == ALL_STYLES)
+ map.put(zones[a][1], a);
+ if (style == SHORT || style == ALL_STYLES)
+ map.put(zones[a][2], a);
+ }
+ return map;
+ }
+ if (field == DST_OFFSET)
+ {
+ String[][] zones = syms.getZoneStrings();
+ for (int a = 0; a < zones.length; ++a)
+ {
+ if (style == LONG || style == ALL_STYLES)
+ map.put(zones[a][3], a);
+ if (style == SHORT || style == ALL_STYLES)
+ map.put(zones[a][4], a);
+ }
+ return map;
+ }
+
+ throw new InternalError("Failed to resolve field " + field +
+ " with style " + style + " for locale " +
+ locale);
+ }
+
}
diff --git a/libjava/classpath/java/util/Collections.java b/libjava/classpath/java/util/Collections.java
index 77ff6ed8fa0..fd802fe9db4 100644
--- a/libjava/classpath/java/util/Collections.java
+++ b/libjava/classpath/java/util/Collections.java
@@ -706,14 +706,16 @@ public class Collections
{
if (!forward)
itr.next(); // Changing direction first.
- for ( ; i != pos; i++, o = itr.next());
+ for ( ; i != pos; i++, o = itr.next())
+ ;
forward = true;
}
else
{
if (forward)
itr.previous(); // Changing direction first.
- for ( ; i != pos; i--, o = itr.previous());
+ for ( ; i != pos; i--, o = itr.previous())
+ ;
forward = false;
}
final int d = compare(o, key, c);
@@ -1460,8 +1462,10 @@ public class Collections
public static int frequency (Collection<?> c, Object o)
{
int result = 0;
- for (Object v : c)
+ final Iterator<?> it = c.iterator();
+ while (it.hasNext())
{
+ Object v = it.next();
if (AbstractCollection.equals(o, v))
++result;
}
@@ -1522,8 +1526,9 @@ public class Collections
public static boolean disjoint(Collection<?> c1, Collection<?> c2)
{
Collection<Object> oc1 = (Collection<Object>) c1;
- for (Object o : oc1)
- if (c2.contains(o))
+ final Iterator<Object> it = oc1.iterator();
+ while (it.hasNext())
+ if (c2.contains(it.next()))
return false;
return true;
}
@@ -5113,7 +5118,7 @@ public class Collections
// The array returned is an array of UnmodifiableMapEntry instead of
// Map.Entry
- public Map.Entry<K,V>[] toArray()
+ public Object[] toArray()
{
Object[] mapEntryResult = super.toArray();
UnmodifiableMapEntry<K,V> result[] = null;
@@ -5127,7 +5132,7 @@ public class Collections
}
return result;
}
-
+
// The array returned is an array of UnmodifiableMapEntry instead of
// Map.Entry
public <S> S[] toArray(S[] array)
@@ -5825,8 +5830,10 @@ public class Collections
public boolean addAll(Collection<? extends E> coll)
{
Collection<E> typedColl = (Collection<E>) c;
- for (E element : typedColl)
+ final Iterator<E> it = typedColl.iterator();
+ while (it.hasNext())
{
+ final E element = it.next();
if (!type.isInstance(element))
throw new ClassCastException("A member of the collection is not of the correct type.");
}
@@ -6167,9 +6174,10 @@ public class Collections
public boolean addAll(int index, Collection<? extends E> coll)
{
Collection<E> typedColl = (Collection<E>) coll;
- for (E element : typedColl)
+ final Iterator<E> it = typedColl.iterator();
+ while (it.hasNext())
{
- if (!type.isInstance(element))
+ if (!type.isInstance(it.next()))
throw new ClassCastException("A member of the collection is not of the correct type.");
}
return list.addAll(index, coll);
@@ -6870,8 +6878,10 @@ public class Collections
public void putAll(Map<? extends K, ? extends V> map)
{
Map<K,V> typedMap = (Map<K,V>) map;
- for (Map.Entry<K,V> entry : typedMap.entrySet())
+ final Iterator<Map.Entry<K,V>> it = typedMap.entrySet().iterator();
+ while (it.hasNext())
{
+ final Map.Entry<K,V> entry = it.next();
if (!keyType.isInstance(entry.getKey()))
throw new ClassCastException("A key is of the wrong type.");
if (!valueType.isInstance(entry.getValue()))
@@ -7423,4 +7433,189 @@ public class Collections
}
} // class CheckedSortedSet
+ /**
+ * Returns a view of a {@link Deque} as a stack or LIFO (Last-In-First-Out)
+ * {@link Queue}. Each call to the LIFO queue corresponds to one
+ * equivalent method call to the underlying deque, with the exception
+ * of {@link Collection#addAll(Collection)}, which is emulated by a series
+ * of {@link Deque#push(E)} calls.
+ *
+ * @param deque the deque to convert to a LIFO queue.
+ * @return a LIFO queue.
+ * @since 1.6
+ */
+ public static <T> Queue<T> asLifoQueue(Deque<T> deque)
+ {
+ return new LIFOQueue<T>(deque);
+ }
+
+ /**
+ * Returns a set backed by the supplied map. The resulting set
+ * has the same performance, concurrency and ordering characteristics
+ * as the original map. The supplied map must be empty and should not
+ * be used after the set is created. Each call to the set corresponds
+ * to one equivalent method call to the underlying map, with the exception
+ * of {@link Set#addAll(Collection)} which is emulated by a series of
+ * calls to <code>put</code>.
+ *
+ * @param map the map to convert to a set.
+ * @return a set backed by the supplied map.
+ * @throws IllegalArgumentException if the map is not empty.
+ * @since 1.6
+ */
+ public static <E> Set<E> newSetFromMap(Map<E,Boolean> map)
+ {
+ return new MapSet<E>(map);
+ }
+
+ /**
+ * The implementation of {@link #asLIFOQueue(Deque)}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+ private static class LIFOQueue<T>
+ extends AbstractQueue<T>
+ {
+
+ /**
+ * The backing deque.
+ */
+ private Deque<T> deque;
+
+ /**
+ * Constructs a new {@link LIFOQueue} with the specified
+ * backing {@link Deque}.
+ *
+ * @param deque the backing deque.
+ */
+ public LIFOQueue(Deque<T> deque)
+ {
+ this.deque = deque;
+ }
+
+ public boolean add(T e)
+ {
+ return deque.offerFirst(e);
+ }
+
+ public boolean addAll(Collection<? extends T> c)
+ {
+ boolean result = false;
+ final Iterator<? extends T> it = c.iterator();
+ while (it.hasNext())
+ result |= deque.offerFirst(it.next());
+ return result;
+ }
+
+ public void clear()
+ {
+ deque.clear();
+ }
+
+ public boolean isEmpty()
+ {
+ return deque.isEmpty();
+ }
+
+ public Iterator<T> iterator()
+ {
+ return deque.iterator();
+ }
+
+ public boolean offer(T e)
+ {
+ return deque.offerFirst(e);
+ }
+
+ public T peek()
+ {
+ return deque.peek();
+ }
+
+ public T poll()
+ {
+ return deque.poll();
+ }
+
+ public int size()
+ {
+ return deque.size();
+ }
+ } // class LIFOQueue
+
+ /**
+ * The implementation of {@link #newSetFromMap(Map)}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+ private static class MapSet<E>
+ extends AbstractSet<E>
+ {
+
+ /**
+ * The backing map.
+ */
+ private Map<E,Boolean> map;
+
+ /**
+ * Constructs a new {@link MapSet} using the specified
+ * backing {@link Map}.
+ *
+ * @param map the backing map.
+ * @throws IllegalArgumentException if the map is not empty.
+ */
+ public MapSet(Map<E,Boolean> map)
+ {
+ if (!map.isEmpty())
+ throw new IllegalArgumentException("The map must be empty.");
+ this.map = map;
+ }
+
+ public boolean add(E e)
+ {
+ return map.put(e, true) == null;
+ }
+
+ public boolean addAll(Collection<? extends E> c)
+ {
+ boolean result = false;
+ final Iterator<? extends E> it = c.iterator();
+ while (it.hasNext())
+ result |= (map.put(it.next(), true) == null);
+ return result;
+ }
+
+ public void clear()
+ {
+ map.clear();
+ }
+
+ public boolean contains(Object o)
+ {
+ return map.containsKey(o);
+ }
+
+ public boolean isEmpty()
+ {
+ return map.isEmpty();
+ }
+
+ public Iterator<E> iterator()
+ {
+ return map.keySet().iterator();
+ }
+
+ public boolean remove(Object o)
+ {
+ return map.remove(o) != null;
+ }
+
+ public int size()
+ {
+ return map.size();
+ }
+ } // class MapSet
+
} // class Collections
diff --git a/libjava/classpath/java/util/Currency.java b/libjava/classpath/java/util/Currency.java
index 32ea7534735..a0933eca2f6 100644
--- a/libjava/classpath/java/util/Currency.java
+++ b/libjava/classpath/java/util/Currency.java
@@ -44,6 +44,8 @@ import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.util.spi.CurrencyNameProvider;
+
/**
* Representation of a currency for a particular locale. Each currency
* is identified by its ISO 4217 code, and only one instance of this
@@ -402,8 +404,35 @@ public final class Currency
*/
public String getSymbol(Locale locale)
{
- return LocaleHelper.getLocalizedString(locale, currencyCode,
- "currenciesSymbol", false, true);
+ String property = "currenciesSymbol." + currencyCode;
+ try
+ {
+ return ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ locale).getString(property);
+ }
+ catch (MissingResourceException exception)
+ {
+ /* This means runtime support for the locale
+ * is not available, so we check providers. */
+ }
+ for (CurrencyNameProvider p :
+ ServiceLoader.load(CurrencyNameProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(locale))
+ {
+ String localizedString = p.getSymbol(currencyCode,
+ locale);
+ if (localizedString != null)
+ return localizedString;
+ break;
+ }
+ }
+ }
+ if (locale.equals(Locale.ROOT)) // Base case
+ return currencyCode;
+ return getSymbol(LocaleHelper.getFallbackLocale(locale));
}
/**
diff --git a/libjava/classpath/java/util/Date.java b/libjava/classpath/java/util/Date.java
index f481753db8d..1ad128ebfc5 100644
--- a/libjava/classpath/java/util/Date.java
+++ b/libjava/classpath/java/util/Date.java
@@ -856,7 +856,7 @@ public class Date
hour += 12;
}
else if (parseDayOfWeek(tok))
- ; // Ignore it; throw the token away.
+ { /* Ignore it; throw the token away. */ }
else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT"))
localTimezone = false;
else if (tok.startsWith("UT") || tok.startsWith("GMT"))
diff --git a/libjava/classpath/java/util/GregorianCalendar.java b/libjava/classpath/java/util/GregorianCalendar.java
index 83ac00e77e0..6eb7ce84eab 100644
--- a/libjava/classpath/java/util/GregorianCalendar.java
+++ b/libjava/classpath/java/util/GregorianCalendar.java
@@ -1,5 +1,5 @@
/* java.util.GregorianCalendar
- Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004
+ Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2007
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -223,7 +223,6 @@ public class GregorianCalendar extends Calendar
{
this(zone, locale, false);
setTimeInMillis(System.currentTimeMillis());
- complete();
}
/**
@@ -842,13 +841,24 @@ public class GregorianCalendar extends Calendar
// which day of the week are we (0..6), relative to getFirstDayOfWeek
int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
- fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7;
+ // which day of the week is the first of this month?
+ // nb 35 is the smallest multiple of 7 that ensures that
+ // the left hand side of the modulo operator is positive.
+ int relativeWeekdayOfFirst = (relativeWeekday - fields[DAY_OF_MONTH]
+ + 1 + 35) % 7;
+
+ // which week of the month is the first of this month in?
+ int minDays = getMinimalDaysInFirstWeek();
+ int weekOfFirst = ((7 - relativeWeekdayOfFirst) >= minDays) ? 1 : 0;
+
+ // which week of the month is this day in?
+ fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH]
+ + relativeWeekdayOfFirst - 1) / 7 + weekOfFirst;
int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
// Do the Correction: getMinimalDaysInFirstWeek() is always in the
// first week.
- int minDays = getMinimalDaysInFirstWeek();
int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays)
- getFirstDayOfWeek()) % 7;
if (minDays - firstWeekday < 1)
diff --git a/libjava/classpath/java/util/HashMap.java b/libjava/classpath/java/util/HashMap.java
index 92022a7d55e..eca3ad6aaf3 100644
--- a/libjava/classpath/java/util/HashMap.java
+++ b/libjava/classpath/java/util/HashMap.java
@@ -380,11 +380,11 @@ public class HashMap<K, V> extends AbstractMap<K, V>
*/
public void putAll(Map<? extends K, ? extends V> m)
{
- Map<K,V> addMap;
-
- addMap = (Map<K,V>) m;
- for (Map.Entry<K,V> e : addMap.entrySet())
+ final Map<K,V> addMap = (Map<K,V>) m;
+ final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator();
+ while (it.hasNext())
{
+ final Map.Entry<K,V> e = it.next();
// Optimize in case the Entry is one of our own.
if (e instanceof AbstractMap.SimpleEntry)
{
@@ -710,12 +710,12 @@ public class HashMap<K, V> extends AbstractMap<K, V>
*/
void putAllInternal(Map<? extends K, ? extends V> m)
{
- Map<K,V> addMap;
-
- addMap = (Map<K,V>) m;
+ final Map<K,V> addMap = (Map<K,V>) m;
+ final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator();
size = 0;
- for (Map.Entry<K,V> e : addMap.entrySet())
+ while (it.hasNext())
{
+ final Map.Entry<K,V> e = it.next();
size++;
K key = e.getKey();
int idx = hash(key);
diff --git a/libjava/classpath/java/util/Hashtable.java b/libjava/classpath/java/util/Hashtable.java
index 2e265a47387..a85674637e7 100644
--- a/libjava/classpath/java/util/Hashtable.java
+++ b/libjava/classpath/java/util/Hashtable.java
@@ -505,12 +505,11 @@ public class Hashtable<K, V> extends Dictionary<K, V>
*/
public synchronized void putAll(Map<? extends K, ? extends V> m)
{
- Map<K,V> addMap;
-
- addMap = (Map<K,V>) m;
-
- for (Map.Entry<K,V> e : addMap.entrySet())
+ final Map<K,V> addMap = (Map<K,V>) m;
+ final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator();
+ while (it.hasNext())
{
+ final Map.Entry<K,V> e = it.next();
// Optimize in case the Entry is one of our own.
if (e instanceof AbstractMap.SimpleEntry)
{
@@ -857,13 +856,12 @@ public class Hashtable<K, V> extends Dictionary<K, V>
*/
void putAllInternal(Map<? extends K, ? extends V> m)
{
- Map<K,V> addMap;
-
- addMap = (Map<K,V>) m;
+ final Map<K,V> addMap = (Map<K,V>) m;
+ final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator();
size = 0;
-
- for (Map.Entry<K,V> e : addMap.entrySet())
+ while (it.hasNext())
{
+ final Map.Entry<K,V> e = it.next();
size++;
K key = e.getKey();
int idx = hash(key);
diff --git a/libjava/classpath/java/util/LinkedList.java b/libjava/classpath/java/util/LinkedList.java
index 2d78573d08c..3f8b2ad60a0 100644
--- a/libjava/classpath/java/util/LinkedList.java
+++ b/libjava/classpath/java/util/LinkedList.java
@@ -1,5 +1,5 @@
/* LinkedList.java -- Linked list implementation of the List interface
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -64,15 +64,17 @@ import java.lang.reflect.Array;
* @author Original author unknown
* @author Bryce McKinlay
* @author Eric Blake (ebb9@email.byu.edu)
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
* @see List
* @see ArrayList
* @see Vector
* @see Collections#synchronizedList(List)
* @since 1.2
- * @status missing javadoc, but complete to 1.4
+ * @status Complete to 1.6
*/
public class LinkedList<T> extends AbstractSequentialList<T>
- implements List<T>, Queue<T>, Cloneable, Serializable
+ implements List<T>, Deque<T>, Cloneable, Serializable
{
/**
* Compatible with JDK 1.2.
@@ -708,6 +710,10 @@ public class LinkedList<T> extends AbstractSequentialList<T>
}
/**
+ * Adds the specified element to the end of the list.
+ *
+ * @param value the value to add.
+ * @return true.
* @since 1.5
*/
public boolean offer(T value)
@@ -716,6 +722,11 @@ public class LinkedList<T> extends AbstractSequentialList<T>
}
/**
+ * Returns the first element of the list without removing
+ * it.
+ *
+ * @return the first element of the list.
+ * @throws NoSuchElementException if the list is empty.
* @since 1.5
*/
public T element()
@@ -724,6 +735,11 @@ public class LinkedList<T> extends AbstractSequentialList<T>
}
/**
+ * Returns the first element of the list without removing
+ * it.
+ *
+ * @return the first element of the list, or <code>null</code>
+ * if the list is empty.
* @since 1.5
*/
public T peek()
@@ -734,6 +750,10 @@ public class LinkedList<T> extends AbstractSequentialList<T>
}
/**
+ * Removes and returns the first element of the list.
+ *
+ * @return the first element of the list, or <code>null</code>
+ * if the list is empty.
* @since 1.5
*/
public T poll()
@@ -744,6 +764,10 @@ public class LinkedList<T> extends AbstractSequentialList<T>
}
/**
+ * Removes and returns the first element of the list.
+ *
+ * @return the first element of the list.
+ * @throws NoSuchElementException if the list is empty.
* @since 1.5
*/
public T remove()
@@ -992,4 +1016,245 @@ public class LinkedList<T> extends AbstractSequentialList<T>
lastReturned.data = o;
}
} // class LinkedListItr
+
+ /**
+ * Obtain an Iterator over this list in reverse sequential order.
+ *
+ * @return an Iterator over the elements of the list in
+ * reverse order.
+ * @since 1.6
+ */
+ public Iterator<T> descendingIterator()
+ {
+ return new Iterator<T>()
+ {
+ /** Number of modifications we know about. */
+ private int knownMod = modCount;
+
+ /** Entry that will be returned by next(). */
+ private Entry<T> next = last;
+
+ /** Entry that will be affected by remove() or set(). */
+ private Entry<T> lastReturned;
+
+ /** Index of `next'. */
+ private int position = size() - 1;
+
+ // This will get inlined, since it is private.
+ /**
+ * Checks for modifications made to the list from
+ * elsewhere while iteration is in progress.
+ *
+ * @throws ConcurrentModificationException if the
+ * list has been modified elsewhere.
+ */
+ private void checkMod()
+ {
+ if (knownMod != modCount)
+ throw new ConcurrentModificationException();
+ }
+
+ /**
+ * Tests to see if there are any more objects to
+ * return.
+ *
+ * @return true if the start of the list has not yet been
+ * reached.
+ */
+ public boolean hasNext()
+ {
+ return next != null;
+ }
+
+ /**
+ * Retrieves the next object from the list.
+ *
+ * @return The next object.
+ * @throws NoSuchElementException if there are
+ * no more objects to retrieve.
+ * @throws ConcurrentModificationException if the
+ * list has been modified elsewhere.
+ */
+ public T next()
+ {
+ checkMod();
+ if (next == null)
+ throw new NoSuchElementException();
+ --position;
+ lastReturned = next;
+ next = lastReturned.previous;
+ return lastReturned.data;
+ }
+
+ /**
+ * Removes the last object retrieved by <code>next()</code>
+ * from the list, if the list supports object removal.
+ *
+ * @throws ConcurrentModificationException if the list
+ * has been modified elsewhere.
+ * @throws IllegalStateException if the iterator is positioned
+ * before the start of the list or the last object has already
+ * been removed.
+ */
+ public void remove()
+ {
+ checkMod();
+ if (lastReturned == null)
+ throw new IllegalStateException();
+ removeEntry(lastReturned);
+ lastReturned = null;
+ ++knownMod;
+ }
+ };
+ }
+
+ /**
+ * Inserts the specified element at the front of the list.
+ *
+ * @param value the element to insert.
+ * @return true.
+ * @since 1.6
+ */
+ public boolean offerFirst(T value)
+ {
+ addFirst(value);
+ return true;
+ }
+
+ /**
+ * Inserts the specified element at the end of the list.
+ *
+ * @param value the element to insert.
+ * @return true.
+ * @since 1.6
+ */
+ public boolean offerLast(T value)
+ {
+ return add(value);
+ }
+
+ /**
+ * Returns the first element of the list without removing
+ * it.
+ *
+ * @return the first element of the list, or <code>null</code>
+ * if the list is empty.
+ * @since 1.6
+ */
+ public T peekFirst()
+ {
+ return peek();
+ }
+
+ /**
+ * Returns the last element of the list without removing
+ * it.
+ *
+ * @return the last element of the list, or <code>null</code>
+ * if the list is empty.
+ * @since 1.6
+ */
+ public T peekLast()
+ {
+ if (size == 0)
+ return null;
+ return getLast();
+ }
+
+ /**
+ * Removes and returns the first element of the list.
+ *
+ * @return the first element of the list, or <code>null</code>
+ * if the list is empty.
+ * @since 1.6
+ */
+ public T pollFirst()
+ {
+ return poll();
+ }
+
+ /**
+ * Removes and returns the last element of the list.
+ *
+ * @return the last element of the list, or <code>null</code>
+ * if the list is empty.
+ * @since 1.6
+ */
+ public T pollLast()
+ {
+ if (size == 0)
+ return null;
+ return removeLast();
+ }
+
+ /**
+ * Pops an element from the stack by removing and returning
+ * the first element in the list. This is equivalent to
+ * calling {@link #removeFirst()}.
+ *
+ * @return the top of the stack, which is the first element
+ * of the list.
+ * @throws NoSuchElementException if the list is empty.
+ * @since 1.6
+ * @see #removeFirst()
+ */
+ public T pop()
+ {
+ return removeFirst();
+ }
+
+ /**
+ * Pushes an element on to the stack by adding it to the
+ * front of the list. This is equivalent to calling
+ * {@link #addFirst(T)}.
+ *
+ * @param value the element to push on to the stack.
+ * @throws NoSuchElementException if the list is empty.
+ * @since 1.6
+ * @see #addFirst(T)
+ */
+ public void push(T value)
+ {
+ addFirst(value);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element
+ * from the list, when traversing the list from head to
+ * tail. The list is unchanged if the element is not found.
+ * This is equivalent to calling {@link #remove(Object)}.
+ *
+ * @param o the element to remove.
+ * @return true if an instance of the object was removed.
+ * @since 1.6
+ */
+ public boolean removeFirstOccurrence(Object o)
+ {
+ return remove(o);
+ }
+
+ /**
+ * Removes the last occurrence of the specified element
+ * from the list, when traversing the list from head to
+ * tail. The list is unchanged if the element is not found.
+ *
+ * @param o the element to remove.
+ * @return true if an instance of the object was removed.
+ * @since 1.6
+ */
+ public boolean removeLastOccurrence(Object o)
+ {
+ Entry<T> e = last;
+ while (e != null)
+ {
+ if (equals(o, e.data))
+ {
+ removeEntry(e);
+ return true;
+ }
+ e = e.previous;
+ }
+ return false;
+ }
+
}
diff --git a/libjava/classpath/java/util/Locale.java b/libjava/classpath/java/util/Locale.java
index 4c91eeb0a48..846ae7baadc 100644
--- a/libjava/classpath/java/util/Locale.java
+++ b/libjava/classpath/java/util/Locale.java
@@ -46,6 +46,8 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.spi.LocaleNameProvider;
+
/**
* Locales represent a specific country and culture. Classes which can be
* passed a Locale object tailor their information for a given locale. For
@@ -161,6 +163,11 @@ public final class Locale implements Serializable, Cloneable
/** Locale which represents the French speaking portion of Canada. */
public static final Locale CANADA_FRENCH = getLocale("fr", "CA");
+ /** The root locale, used as the base case in lookups by
+ * locale-sensitive operations.
+ */
+ public static final Locale ROOT = new Locale("","","");
+
/**
* Compatible with JDK 1.1+.
*/
@@ -674,6 +681,8 @@ public final class Locale implements Serializable, Cloneable
*/
public String getDisplayLanguage(Locale inLocale)
{
+ if (language.isEmpty())
+ return "";
try
{
ResourceBundle res =
@@ -685,8 +694,27 @@ public final class Locale implements Serializable, Cloneable
}
catch (MissingResourceException e)
{
- return language;
+ /* This means runtime support for the locale
+ * is not available, so we check providers. */
}
+ for (LocaleNameProvider p :
+ ServiceLoader.load(LocaleNameProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(inLocale))
+ {
+ String locLang = p.getDisplayLanguage(language,
+ inLocale);
+ if (locLang != null)
+ return locLang;
+ break;
+ }
+ }
+ }
+ if (inLocale.equals(Locale.ROOT)) // Base case
+ return language;
+ return getDisplayLanguage(LocaleHelper.getFallbackLocale(inLocale));
}
/**
@@ -732,6 +760,8 @@ public final class Locale implements Serializable, Cloneable
*/
public String getDisplayCountry(Locale inLocale)
{
+ if (country.isEmpty())
+ return "";
try
{
ResourceBundle res =
@@ -743,8 +773,27 @@ public final class Locale implements Serializable, Cloneable
}
catch (MissingResourceException e)
{
- return country;
+ /* This means runtime support for the locale
+ * is not available, so we check providers. */
}
+ for (LocaleNameProvider p :
+ ServiceLoader.load(LocaleNameProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(inLocale))
+ {
+ String locCountry = p.getDisplayCountry(country,
+ inLocale);
+ if (locCountry != null)
+ return locCountry;
+ break;
+ }
+ }
+ }
+ if (inLocale.equals(Locale.ROOT)) // Base case
+ return country;
+ return getDisplayCountry(LocaleHelper.getFallbackLocale(inLocale));
}
/**
@@ -791,6 +840,8 @@ public final class Locale implements Serializable, Cloneable
*/
public String getDisplayVariant(Locale inLocale)
{
+ if (variant.isEmpty())
+ return "";
try
{
ResourceBundle res =
@@ -802,8 +853,27 @@ public final class Locale implements Serializable, Cloneable
}
catch (MissingResourceException e)
{
- return variant;
+ /* This means runtime support for the locale
+ * is not available, so we check providers. */
+ }
+ for (LocaleNameProvider p :
+ ServiceLoader.load(LocaleNameProvider.class))
+ {
+ for (Locale loc : p.getAvailableLocales())
+ {
+ if (loc.equals(inLocale))
+ {
+ String locVar = p.getDisplayVariant(variant,
+ inLocale);
+ if (locVar != null)
+ return locVar;
+ break;
+ }
+ }
}
+ if (inLocale.equals(Locale.ROOT)) // Base case
+ return country;
+ return getDisplayVariant(LocaleHelper.getFallbackLocale(inLocale));
}
/**
diff --git a/libjava/classpath/java/util/PriorityQueue.java b/libjava/classpath/java/util/PriorityQueue.java
index c9cfd8b0fba..9e738d6e99c 100644
--- a/libjava/classpath/java/util/PriorityQueue.java
+++ b/libjava/classpath/java/util/PriorityQueue.java
@@ -164,6 +164,7 @@ public class PriorityQueue<E> extends AbstractQueue<E> implements Serializable
{
while (storage[++index] == null)
;
+
++count;
return storage[index];
}
diff --git a/libjava/classpath/java/util/ServiceConfigurationError.java b/libjava/classpath/java/util/ServiceConfigurationError.java
new file mode 100644
index 00000000000..1d006c8de20
--- /dev/null
+++ b/libjava/classpath/java/util/ServiceConfigurationError.java
@@ -0,0 +1,94 @@
+/* ServiceConfigurationError.java -- An error on service loading.
+ Copyright (C) 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util;
+
+/**
+ * <p>
+ * An error thrown when a problem occurs during the loading
+ * of a service provider by a {@link ServiceLoader}. Such
+ * an error can occur for a number of reasons:
+ * </p>
+ * <ul>
+ * <li>An I/O error occurs</li>
+ * <li>The configuration file doesn't meet the specifications</li>
+ * <li>A listed class can not be found</li>
+ * <li>A listed class does not implement the service</li>
+ * <li>A listed class can not be instantiated</li>
+ * </ul>
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public class ServiceConfigurationError
+ extends Error
+{
+
+ /**
+ * Compatible with JDK 1.6
+ */
+ private static final long serialVersionUID = 74132770414881L;
+
+ /**
+ * Constructs a new {@link ServiceConfigurationError}
+ * with the specified message.
+ *
+ * @param message a message describing the error, or
+ * <code>null</code> if none is required.
+ */
+ public ServiceConfigurationError(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link ServiceConfigurationError}
+ * with the specified message and cause.
+ *
+ * @param message a message describing the error, or
+ * <code>null</code> if none is required.
+ * @param cause the cause of the error, or
+ * <code>null</code> if this is unknown
+ * or inappropriate.
+ */
+ public ServiceConfigurationError(String message,
+ Throwable cause)
+ {
+ super(message,cause);
+ }
+
+}
diff --git a/libjava/classpath/java/util/ServiceLoader.java b/libjava/classpath/java/util/ServiceLoader.java
new file mode 100644
index 00000000000..9935416359e
--- /dev/null
+++ b/libjava/classpath/java/util/ServiceLoader.java
@@ -0,0 +1,274 @@
+/* ServiceLoader.java -- Allows loading of plug-in services.
+ Copyright (C) 2006, 2007 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util;
+
+import gnu.classpath.ServiceFactory;
+
+/**
+ * <p>
+ * Facilities for loading service providers. A service is
+ * defined by a set of interfaces or abstract classes, and
+ * a service provider gives a concrete implementation of this.
+ * Service providers may be installed as part of the runtime
+ * environment using JAR files in the extension directories,
+ * or may be simply supplied on the classpath.
+ * </p>
+ * <p>
+ * In terms of loading a service, the service is defined by
+ * a single interface or abstract class which the provider
+ * implements. This may not constitute the entire service,
+ * but is simply a mechanism by which a provider of the
+ * service can be loaded and its capabilities determined.
+ * The variety of possible services means that no more
+ * requirements are made of the service provider other than
+ * that it must have an accessible zero argument constructor
+ * in order to allow an instance to be created.
+ * </p>
+ * <p>
+ * Service providers are listed in a file named after the
+ * service type in the directory <code>META-INF/services</code>.
+ * The file contains a list of classes, and must be encoded
+ * using UTF-8. Whitespace is ignored. Comments can be
+ * included by using a <code>'#'</code> prefix; anything occurring
+ * on the same line after this symbol is ignored. Duplicate classes
+ * are ignored.
+ * </p>
+ * <p>
+ * The classes are loaded using the same classloader that was
+ * queried in order to locate the configuration file. As a result,
+ * the providers do not need to reside in the same JAR file as the
+ * resource; they merely have to be accessible to this classloader,
+ * which may differ from the one that loaded the file itself.
+ * </p>
+ * <p>
+ * Providers are located and instantiated lazily, as calls to the
+ * {@link #iterator()} are made. Providers are cached, and those in
+ * the cache are returned first. The cache may be cleared by calling
+ * {@link #reload()}. Service loaders always execute in the security
+ * context of the caller, so ideally calls should be made from a trusted
+ * source.
+ * </p>
+ * <p>
+ * Note that this class is not thread-safe, and that strange errors may
+ * occur as the result of the use of remote URLs occurring on the classpath,
+ * which lead to erroneous web pages.
+ * </p>
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public final class ServiceLoader<S>
+ implements Iterable<S>
+{
+
+ /**
+ * The class of the service provider.
+ */
+ private Class<S> spi;
+
+ /**
+ * The class loader for the service provider.
+ */
+ private ClassLoader loader;
+
+ /**
+ * The cache of service providers.
+ */
+ private List<S> cache;
+
+ /**
+ * The {@link gnu.classpath.ServiceFactory} iterator
+ * from which providers are obtained.
+ */
+ private Iterator<S> serviceIt;
+
+ /**
+ * Constructs a new {@link ServiceLoader} with
+ * the specified provider and class loader.
+ *
+ * @param spi the service to load.
+ * @param loader the class loader to use.
+ */
+ private ServiceLoader(Class<S> spi, ClassLoader loader)
+ {
+ this.spi = spi;
+ this.loader = loader;
+ cache = new ArrayList<S>();
+ }
+
+ /**
+ * Lazily loads the available providers. The iterator first returns
+ * providers from the cache, in instantiation order, followed by any
+ * remaining providers, which are added to the cache after loading.
+ * The actual loading and parsing of the configuration file takes
+ * place in the {@link Iterator#hasNext()} and {@link Iterator#next()}
+ * methods, which means that they may result in a
+ * {@link ServiceConfigurationError} being thrown. If such an error
+ * does occur, subsequent invocations will attempt to recover.
+ * The {@link remove()} method is not supported and instead throws
+ * an {@link UnsupportedOperationException}.
+ *
+ * @return an iterator that lazily loads service providers.
+ */
+ public Iterator<S> iterator()
+ {
+ return new Iterator<S>()
+ {
+ /**
+ * The cache iterator.
+ */
+ private Iterator<S> cacheIt = cache.iterator();
+
+ public boolean hasNext()
+ {
+ if (cacheIt.hasNext())
+ return true;
+ if (serviceIt == null)
+ serviceIt =
+ ServiceFactory.lookupProviders(spi, loader, true);
+ return serviceIt.hasNext();
+ }
+
+ public S next()
+ {
+ if (cacheIt.hasNext())
+ return cacheIt.next();
+ if (serviceIt == null)
+ serviceIt =
+ ServiceFactory.lookupProviders(spi, loader, true);
+ S nextService = serviceIt.next();
+ cache.add(nextService);
+ return nextService;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Creates a new service loader for the given service,
+ * using the context class loader of the current thread.
+ * This is equivalent to calling <code>ServiceLoader.load(service,
+ * Thread.currentThread().getContextClassLoader())</code>.
+ *
+ * @param service the interface or abstract class that represents
+ * the service.
+ * @return a new {@link ServiceLoader} instance.
+ */
+ public static <S> ServiceLoader<S> load(Class<S> service)
+ {
+ return load(service,
+ Thread.currentThread().getContextClassLoader());
+ }
+
+ /**
+ * Creates a new service loader for the given service,
+ * using the specified class loader. The class loader is
+ * used to access the configuration file and the service
+ * provider instances themselves. If the loader is
+ * <code>null</code>, the system class loader (or, if
+ * this is also <code>null</code>, the bootstrap class
+ * loader).
+ *
+ * @param service the interface or abstract class that represents
+ * the service.
+ * @param loader the class loader used to load the configuration
+ * file and service providers.
+ * @return a new {@link ServiceLoader} instance.
+ */
+ public static <S> ServiceLoader<S> load(Class<S> service,
+ ClassLoader loader)
+ {
+ if (loader == null)
+ loader = ClassLoader.getSystemClassLoader();
+ return new ServiceLoader(service, loader);
+ }
+
+ /**
+ * Creates a new service loader for the given service,
+ * using the extension class loader. If the extension
+ * class loader can not be found, the system class loader
+ * is used (or, if this is <code>null</code>, the
+ * bootstrap class loader). The primary use of this method
+ * is to only obtain installed services, ignoring any which
+ * may appear on the classpath. This is equivalent to calling
+ * <code>load(service, extClassLoader)</code> where
+ * <code>extClassLoader</code> is the extension class loader
+ * (or <code>null</code> if this is unavailable).
+ *
+ * @param service the interface or abstract class that represents
+ * the service.
+ * @return a new {@link ServiceLoader} instance.
+ */
+ public static <S> ServiceLoader<S> loadInstalled(Class<S> service)
+ {
+ /* We expect the extension class loader to be the parent
+ * of the system class loader, as in
+ * ClassLoader.getDefaultSystemClassLoader() */
+ return load(service,
+ ClassLoader.getSystemClassLoader().getParent());
+ }
+
+ /**
+ * Clears the cache of the provider, so that all providers
+ * are again read from the configuration file and instantiated.
+ */
+ public void reload()
+ {
+ cache.clear();
+ }
+
+ /**
+ * Returns a textual representation of this
+ * {@link ServiceLoader}.
+ *
+ * @return a textual representation of the
+ * service loader.
+ */
+ public String toString()
+ {
+ return getClass().getName() +
+ "[spi=" + spi +
+ ",loader=" + loader +
+ "]";
+ }
+
+}
diff --git a/libjava/classpath/java/util/StringTokenizer.java b/libjava/classpath/java/util/StringTokenizer.java
index 0b59abe2fda..b230c73d869 100644
--- a/libjava/classpath/java/util/StringTokenizer.java
+++ b/libjava/classpath/java/util/StringTokenizer.java
@@ -181,13 +181,15 @@ public class StringTokenizer implements Enumeration<Object>
{
if (retDelims)
return str.substring(pos, ++pos);
- while (++pos < len && delim.indexOf(str.charAt(pos)) >= 0);
+ while (++pos < len && delim.indexOf(str.charAt(pos)) >= 0)
+ ;
}
if (pos < len)
{
int start = pos;
- while (++pos < len && delim.indexOf(str.charAt(pos)) < 0);
-
+ while (++pos < len && delim.indexOf(str.charAt(pos)) < 0)
+ ;
+
return str.substring(start, pos);
}
throw new NoSuchElementException();
diff --git a/libjava/classpath/java/util/TreeMap.java b/libjava/classpath/java/util/TreeMap.java
index 88abce10d8d..f54cbc336ec 100644
--- a/libjava/classpath/java/util/TreeMap.java
+++ b/libjava/classpath/java/util/TreeMap.java
@@ -1,6 +1,6 @@
/* TreeMap.java -- a class providing a basic Red-Black Tree data structure,
mapping Object --> Object
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -79,6 +79,7 @@ import java.io.Serializable;
* @author Jon Zeppieri
* @author Bryce McKinlay
* @author Eric Blake (ebb9@email.byu.edu)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
* @see Map
* @see HashMap
* @see Hashtable
@@ -88,10 +89,10 @@ import java.io.Serializable;
* @see Collection
* @see Collections#synchronizedSortedMap(SortedMap)
* @since 1.2
- * @status updated to 1.4
+ * @status updated to 1.6
*/
public class TreeMap<K, V> extends AbstractMap<K, V>
- implements SortedMap<K, V>, Cloneable, Serializable
+ implements NavigableMap<K, V>, Cloneable, Serializable
{
// Implementation note:
// A red-black tree is a binary search tree with the additional properties
@@ -143,6 +144,16 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
private transient Set<Map.Entry<K,V>> entries;
/**
+ * The cache for {@link #descendingMap()}.
+ */
+ private transient NavigableMap<K,V> descendingMap;
+
+ /**
+ * The cache for {@link #navigableKeySet()}.
+ */
+ private transient NavigableSet<K> nKeys;
+
+ /**
* Counts the number of modifications this TreeMap has undergone, used
* by Iterators to know when to throw ConcurrentModificationExceptions.
* Package visible for use by nested classes.
@@ -369,46 +380,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
if (entries == null)
// Create an AbstractSet with custom implementations of those methods
// that can be overriden easily and efficiently.
- entries = new AbstractSet<Map.Entry<K,V>>()
- {
- public int size()
- {
- return size;
- }
-
- public Iterator<Map.Entry<K,V>> iterator()
- {
- return new TreeIterator(ENTRIES);
- }
-
- public void clear()
- {
- TreeMap.this.clear();
- }
-
- public boolean contains(Object o)
- {
- if (! (o instanceof Map.Entry))
- return false;
- Map.Entry<K,V> me = (Map.Entry<K,V>) o;
- Node<K,V> n = getNode(me.getKey());
- return n != nil && AbstractSet.equals(me.getValue(), n.value);
- }
-
- public boolean remove(Object o)
- {
- if (! (o instanceof Map.Entry))
- return false;
- Map.Entry<K,V> me = (Map.Entry<K,V>) o;
- Node<K,V> n = getNode(me.getKey());
- if (n != nil && AbstractSet.equals(me.getValue(), n.value))
- {
- removeNode(n);
- return true;
- }
- return false;
- }
- };
+ entries = new NavigableEntrySet();
return entries;
}
@@ -451,7 +423,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
* in one appear in the other. The submap will throw an
* {@link IllegalArgumentException} for any attempt to access or add an
* element beyond the specified cutoff. The returned map does not include
- * the endpoint; if you want inclusion, pass the successor element.
+ * the endpoint; if you want inclusion, pass the successor element
+ * or call <code>headMap(toKey, true)</code>. This is equivalent to
+ * calling <code>headMap(toKey, false)</code>.
*
* @param toKey the (exclusive) cutoff point
* @return a view of the map less than the cutoff
@@ -462,7 +436,29 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
*/
public SortedMap<K, V> headMap(K toKey)
{
- return new SubMap((K)(Object)nil, toKey);
+ return headMap(toKey, false);
+ }
+
+ /**
+ * Returns a view of this Map including all entries with keys less than
+ * (or equal to, if <code>inclusive</code> is true) <code>toKey</code>.
+ * The returned map is backed by the original, so changes in one appear
+ * in the other. The submap will throw an {@link IllegalArgumentException}
+ * for any attempt to access or add an element beyond the specified cutoff.
+ *
+ * @param toKey the cutoff point
+ * @param inclusive true if the cutoff point should be included.
+ * @return a view of the map less than (or equal to, if <code>inclusive</code>
+ * is true) the cutoff.
+ * @throws ClassCastException if <code>toKey</code> is not compatible with
+ * the comparator (or is not Comparable, for natural ordering)
+ * @throws NullPointerException if toKey is null, but the comparator does not
+ * tolerate null elements
+ */
+ public NavigableMap<K, V> headMap(K toKey, boolean inclusive)
+ {
+ return new SubMap((K)(Object)nil, inclusive
+ ? successor(getNode(toKey)).key : toKey);
}
/**
@@ -479,37 +475,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
if (keys == null)
// Create an AbstractSet with custom implementations of those methods
// that can be overriden easily and efficiently.
- keys = new AbstractSet<K>()
- {
- public int size()
- {
- return size;
- }
-
- public Iterator<K> iterator()
- {
- return new TreeIterator(KEYS);
- }
-
- public void clear()
- {
- TreeMap.this.clear();
- }
-
- public boolean contains(Object o)
- {
- return containsKey(o);
- }
-
- public boolean remove(Object key)
- {
- Node<K,V> n = getNode((K) key);
- if (n == nil)
- return false;
- removeNode(n);
- return true;
- }
- };
+ keys = new KeySet();
return keys;
}
@@ -648,7 +614,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
* {@link IllegalArgumentException} for any attempt to access or add an
* element beyond the specified cutoffs. The returned map includes the low
* endpoint but not the high; if you want to reverse this behavior on
- * either end, pass in the successor element.
+ * either end, pass in the successor element or call
+ * {@link #subMap(K,boolean,K,boolean)}. This call is equivalent to
+ * <code>subMap(fromKey, true, toKey, false)</code>.
*
* @param fromKey the (inclusive) low cutoff point
* @param toKey the (exclusive) high cutoff point
@@ -661,7 +629,34 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
*/
public SortedMap<K, V> subMap(K fromKey, K toKey)
{
- return new SubMap(fromKey, toKey);
+ return subMap(fromKey, true, toKey, false);
+ }
+
+ /**
+ * Returns a view of this Map including all entries with keys greater (or
+ * equal to, if <code>fromInclusive</code> is true) <code>fromKey</code> and
+ * less than (or equal to, if <code>toInclusive</code> is true)
+ * <code>toKey</code>. The returned map is backed by the original, so
+ * changes in one appear in the other. The submap will throw an
+ * {@link IllegalArgumentException} for any attempt to access or add an
+ * element beyond the specified cutoffs.
+ *
+ * @param fromKey the low cutoff point
+ * @param fromInclusive true if the low cutoff point should be included.
+ * @param toKey the high cutoff point
+ * @param toInclusive true if the high cutoff point should be included.
+ * @return a view of the map for the specified range.
+ * @throws ClassCastException if either cutoff is not compatible with
+ * the comparator (or is not Comparable, for natural ordering)
+ * @throws NullPointerException if fromKey or toKey is null, but the
+ * comparator does not tolerate null elements
+ * @throws IllegalArgumentException if fromKey is greater than toKey
+ */
+ public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive,
+ K toKey, boolean toInclusive)
+ {
+ return new SubMap(fromInclusive ? fromKey : successor(getNode(fromKey)).key,
+ toInclusive ? successor(getNode(toKey)).key : toKey);
}
/**
@@ -671,6 +666,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
* {@link IllegalArgumentException} for any attempt to access or add an
* element beyond the specified cutoff. The returned map includes the
* endpoint; if you want to exclude it, pass in the successor element.
+ * This is equivalent to calling <code>tailMap(fromKey, true)</code>.
*
* @param fromKey the (inclusive) low cutoff point
* @return a view of the map above the cutoff
@@ -681,7 +677,29 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
*/
public SortedMap<K, V> tailMap(K fromKey)
{
- return new SubMap(fromKey, (K)(Object)nil);
+ return tailMap(fromKey, true);
+ }
+
+ /**
+ * Returns a view of this Map including all entries with keys greater or
+ * equal to <code>fromKey</code>. The returned map is backed by the
+ * original, so changes in one appear in the other. The submap will throw an
+ * {@link IllegalArgumentException} for any attempt to access or add an
+ * element beyond the specified cutoff. The returned map includes the
+ * endpoint; if you want to exclude it, pass in the successor element.
+ *
+ * @param fromKey the low cutoff point
+ * @param inclusive true if the cutoff point should be included.
+ * @return a view of the map above the cutoff
+ * @throws ClassCastException if <code>fromKey</code> is not compatible with
+ * the comparator (or is not Comparable, for natural ordering)
+ * @throws NullPointerException if fromKey is null, but the comparator
+ * does not tolerate null elements
+ */
+ public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive)
+ {
+ return new SubMap(inclusive ? fromKey : successor(getNode(fromKey)).key,
+ (K)(Object)nil);
}
/**
@@ -972,6 +990,21 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
*/
final Node<K,V> highestLessThan(K key)
{
+ return highestLessThan(key, false);
+ }
+
+ /**
+ * Find the "highest" node which is &lt; (or equal to,
+ * if <code>equal</code> is true) key. If key is nil,
+ * return last node. Package visible for use by nested
+ * classes.
+ *
+ * @param key the upper bound, exclusive
+ * @param equal true if the key should be returned if found.
+ * @return the previous node
+ */
+ final Node<K,V> highestLessThan(K key, boolean equal)
+ {
if (key == nil)
return lastNode();
@@ -988,9 +1021,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
else if (comparison < 0)
current = current.left;
else // Exact match.
- return predecessor(last);
+ return (equal ? last : predecessor(last));
}
- return comparison <= 0 ? predecessor(last) : last;
+ return comparison < 0 ? predecessor(last) : last;
}
/**
@@ -1084,8 +1117,8 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
/**
* Find the "lowest" node which is &gt;= key. If key is nil, return either
- * nil or the first node, depending on the parameter first.
- * Package visible for use by nested classes.
+ * nil or the first node, depending on the parameter first. Package visible
+ * for use by nested classes.
*
* @param key the lower bound, inclusive
* @param first true to return the first element instead of nil for nil key
@@ -1093,6 +1126,21 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
*/
final Node<K,V> lowestGreaterThan(K key, boolean first)
{
+ return lowestGreaterThan(key, first, true);
+ }
+
+ /**
+ * Find the "lowest" node which is &gt; (or equal to, if <code>equal</code>
+ * is true) key. If key is nil, return either nil or the first node, depending
+ * on the parameter first. Package visible for use by nested classes.
+ *
+ * @param key the lower bound, inclusive
+ * @param first true to return the first element instead of nil for nil key
+ * @param equal true if the key should be returned if found.
+ * @return the next node
+ */
+ final Node<K,V> lowestGreaterThan(K key, boolean first, boolean equal)
+ {
if (key == nil)
return first ? firstNode() : nil;
@@ -1109,7 +1157,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
else if (comparison < 0)
current = current.left;
else
- return current;
+ return (equal ? current : successor(current));
}
return comparison > 0 ? successor(last) : last;
}
@@ -1409,11 +1457,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
*/
TreeIterator(int type)
{
- // FIXME gcj cannot handle this. Bug java/4695
- // this(type, firstNode(), nil);
- this.type = type;
- this.next = firstNode();
- this.max = nil;
+ this(type, firstNode(), nil);
}
/**
@@ -1489,26 +1533,36 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
*
* @author Eric Blake (ebb9@email.byu.edu)
*/
- private final class SubMap<SK extends K,SV extends V>
- extends AbstractMap<SK,SV>
- implements SortedMap<SK,SV>
+ private final class SubMap
+ extends AbstractMap<K,V>
+ implements NavigableMap<K,V>
{
/**
* The lower range of this view, inclusive, or nil for unbounded.
* Package visible for use by nested classes.
*/
- final SK minKey;
+ final K minKey;
/**
* The upper range of this view, exclusive, or nil for unbounded.
* Package visible for use by nested classes.
*/
- final SK maxKey;
+ final K maxKey;
/**
* The cache for {@link #entrySet()}.
*/
- private Set<Map.Entry<SK,SV>> entries;
+ private Set<Map.Entry<K,V>> entries;
+
+ /**
+ * The cache for {@link #descendingMap()}.
+ */
+ private NavigableMap<K,V> descendingMap;
+
+ /**
+ * The cache for {@link #navigableKeySet()}.
+ */
+ private NavigableSet<K> nKeys;
/**
* Create a SubMap representing the elements between minKey (inclusive)
@@ -1519,9 +1573,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
* @param maxKey the upper bound
* @throws IllegalArgumentException if minKey &gt; maxKey
*/
- SubMap(SK minKey, SK maxKey)
+ SubMap(K minKey, K maxKey)
{
- if (minKey != nil && maxKey != nil && compare((K) minKey, (K) maxKey) > 0)
+ if (minKey != nil && maxKey != nil && compare(minKey, maxKey) > 0)
throw new IllegalArgumentException("fromKey > toKey");
this.minKey = minKey;
this.maxKey = maxKey;
@@ -1535,12 +1589,41 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
* @param key the key to check
* @return true if the key is in range
*/
- boolean keyInRange(SK key)
+ boolean keyInRange(K key)
{
- return ((minKey == nil || compare((K) key, (K) minKey) >= 0)
- && (maxKey == nil || compare((K) key, (K) maxKey) < 0));
+ return ((minKey == nil || compare(key, minKey) >= 0)
+ && (maxKey == nil || compare(key, maxKey) < 0));
}
+ public Entry<K,V> ceilingEntry(K key)
+ {
+ Entry<K,V> n = TreeMap.this.ceilingEntry(key);
+ if (n != null && keyInRange(n.getKey()))
+ return n;
+ return null;
+ }
+
+ public K ceilingKey(K key)
+ {
+ K found = TreeMap.this.ceilingKey(key);
+ if (keyInRange(found))
+ return found;
+ else
+ return null;
+ }
+
+ public NavigableSet<K> descendingKeySet()
+ {
+ return descendingMap().navigableKeySet();
+ }
+
+ public NavigableMap<K,V> descendingMap()
+ {
+ if (descendingMap == null)
+ descendingMap = new DescendingMap(this);
+ return descendingMap;
+ }
+
public void clear()
{
Node next = lowestGreaterThan(minKey, true);
@@ -1553,14 +1636,14 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
}
}
- public Comparator<? super SK> comparator()
+ public Comparator<? super K> comparator()
{
return comparator;
}
public boolean containsKey(Object key)
{
- return keyInRange((SK) key) && TreeMap.this.containsKey(key);
+ return keyInRange((K) key) && TreeMap.this.containsKey(key);
}
public boolean containsValue(Object value)
@@ -1576,150 +1659,160 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
return false;
}
- public Set<Map.Entry<SK,SV>> entrySet()
+ public Set<Map.Entry<K,V>> entrySet()
{
if (entries == null)
// Create an AbstractSet with custom implementations of those methods
// that can be overriden easily and efficiently.
- entries = new AbstractSet<Map.Entry<SK,SV>>()
- {
- public int size()
- {
- return SubMap.this.size();
- }
-
- public Iterator<Map.Entry<SK,SV>> iterator()
- {
- Node first = lowestGreaterThan(minKey, true);
- Node max = lowestGreaterThan(maxKey, false);
- return new TreeIterator(ENTRIES, first, max);
- }
-
- public void clear()
- {
- SubMap.this.clear();
- }
-
- public boolean contains(Object o)
- {
- if (! (o instanceof Map.Entry))
- return false;
- Map.Entry<SK,SV> me = (Map.Entry<SK,SV>) o;
- SK key = me.getKey();
- if (! keyInRange(key))
- return false;
- Node<K,V> n = getNode((K) key);
- return n != nil && AbstractSet.equals(me.getValue(), n.value);
- }
-
- public boolean remove(Object o)
- {
- if (! (o instanceof Map.Entry))
- return false;
- Map.Entry<SK,SV> me = (Map.Entry<SK,SV>) o;
- SK key = me.getKey();
- if (! keyInRange(key))
- return false;
- Node<K,V> n = getNode((K) key);
- if (n != nil && AbstractSet.equals(me.getValue(), n.value))
- {
- removeNode(n);
- return true;
- }
- return false;
- }
- };
+ entries = new SubMap.NavigableEntrySet();
return entries;
}
- public SK firstKey()
+ public Entry<K,V> firstEntry()
{
- Node<SK,SV> node = (Node<SK,SV>) lowestGreaterThan(minKey, true);
+ Node<K,V> node = lowestGreaterThan(minKey, true);
if (node == nil || ! keyInRange(node.key))
+ return null;
+ return node;
+ }
+
+ public K firstKey()
+ {
+ Entry<K,V> e = firstEntry();
+ if (e == null)
throw new NoSuchElementException();
- return node.key;
+ return e.getKey();
}
- public SV get(Object key)
+ public Entry<K,V> floorEntry(K key)
{
- if (keyInRange((SK) key))
- return (SV) TreeMap.this.get(key);
+ Entry<K,V> n = TreeMap.this.floorEntry(key);
+ if (n != null && keyInRange(n.getKey()))
+ return n;
return null;
}
- public SortedMap<SK,SV> headMap(SK toKey)
+ public K floorKey(K key)
{
- if (! keyInRange(toKey))
- throw new IllegalArgumentException("key outside range");
- return new SubMap(minKey, toKey);
+ K found = TreeMap.this.floorKey(key);
+ if (keyInRange(found))
+ return found;
+ else
+ return null;
+ }
+
+ public V get(Object key)
+ {
+ if (keyInRange((K) key))
+ return TreeMap.this.get(key);
+ return null;
}
- public Set<SK> keySet()
+ public SortedMap<K,V> headMap(K toKey)
+ {
+ return headMap(toKey, false);
+ }
+
+ public NavigableMap<K,V> headMap(K toKey, boolean inclusive)
+ {
+ if (!keyInRange(toKey))
+ throw new IllegalArgumentException("Key outside submap range");
+ return new SubMap(minKey, (inclusive ?
+ successor(getNode(toKey)).key : toKey));
+ }
+
+ public Set<K> keySet()
{
if (this.keys == null)
// Create an AbstractSet with custom implementations of those methods
// that can be overriden easily and efficiently.
- this.keys = new AbstractSet()
- {
- public int size()
- {
- return SubMap.this.size();
- }
-
- public Iterator<SK> iterator()
- {
- Node first = lowestGreaterThan(minKey, true);
- Node max = lowestGreaterThan(maxKey, false);
- return new TreeIterator(KEYS, first, max);
- }
+ this.keys = new SubMap.KeySet();
+ return this.keys;
+ }
- public void clear()
- {
- SubMap.this.clear();
- }
+ public Entry<K,V> higherEntry(K key)
+ {
+ Entry<K,V> n = TreeMap.this.higherEntry(key);
+ if (n != null && keyInRange(n.getKey()))
+ return n;
+ return null;
+ }
- public boolean contains(Object o)
- {
- if (! keyInRange((SK) o))
- return false;
- return getNode((K) o) != nil;
- }
+ public K higherKey(K key)
+ {
+ K found = TreeMap.this.higherKey(key);
+ if (keyInRange(found))
+ return found;
+ else
+ return null;
+ }
- public boolean remove(Object o)
- {
- if (! keyInRange((SK) o))
- return false;
- Node n = getNode((K) o);
- if (n != nil)
- {
- removeNode(n);
- return true;
- }
- return false;
- }
- };
- return this.keys;
+ public Entry<K,V> lastEntry()
+ {
+ return lowerEntry(maxKey);
}
- public SK lastKey()
+ public K lastKey()
{
- Node<SK,SV> node = (Node<SK,SV>) highestLessThan(maxKey);
- if (node == nil || ! keyInRange(node.key))
+ Entry<K,V> e = lastEntry();
+ if (e == null)
throw new NoSuchElementException();
- return (SK) node.key;
+ return e.getKey();
+ }
+
+ public Entry<K,V> lowerEntry(K key)
+ {
+ Entry<K,V> n = TreeMap.this.lowerEntry(key);
+ if (n != null && keyInRange(n.getKey()))
+ return n;
+ return null;
+ }
+
+ public K lowerKey(K key)
+ {
+ K found = TreeMap.this.lowerKey(key);
+ if (keyInRange(found))
+ return found;
+ else
+ return null;
+ }
+
+ public NavigableSet<K> navigableKeySet()
+ {
+ if (this.nKeys == null)
+ // Create an AbstractSet with custom implementations of those methods
+ // that can be overriden easily and efficiently.
+ this.nKeys = new SubMap.NavigableKeySet();
+ return this.nKeys;
+ }
+
+ public Entry<K,V> pollFirstEntry()
+ {
+ Entry<K,V> e = firstEntry();
+ if (e != null)
+ removeNode((Node<K,V>) e);
+ return e;
}
- public SV put(SK key, SV value)
+ public Entry<K,V> pollLastEntry()
+ {
+ Entry<K,V> e = lastEntry();
+ if (e != null)
+ removeNode((Node<K,V>) e);
+ return e;
+ }
+
+ public V put(K key, V value)
{
if (! keyInRange(key))
throw new IllegalArgumentException("Key outside range");
- return (SV) TreeMap.this.put(key, value);
+ return TreeMap.this.put(key, value);
}
- public SV remove(Object key)
+ public V remove(Object key)
{
- if (keyInRange((SK)key))
- return (SV) TreeMap.this.remove(key);
+ if (keyInRange((K)key))
+ return TreeMap.this.remove(key);
return null;
}
@@ -1736,21 +1829,34 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
return count;
}
- public SortedMap<SK, SV> subMap(SK fromKey, SK toKey)
+ public SortedMap<K,V> subMap(K fromKey, K toKey)
+ {
+ return subMap(fromKey, true, toKey, false);
+ }
+
+ public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+ K toKey, boolean toInclusive)
{
if (! keyInRange(fromKey) || ! keyInRange(toKey))
throw new IllegalArgumentException("key outside range");
- return new SubMap(fromKey, toKey);
+ return new SubMap(fromInclusive ? fromKey : successor(getNode(fromKey)).key,
+ toInclusive ? successor(getNode(toKey)).key : toKey);
}
- public SortedMap<SK, SV> tailMap(SK fromKey)
+ public SortedMap<K, V> tailMap(K fromKey)
+ {
+ return tailMap(fromKey, true);
+ }
+
+ public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive)
{
if (! keyInRange(fromKey))
throw new IllegalArgumentException("key outside range");
- return new SubMap(fromKey, maxKey);
+ return new SubMap(inclusive ? fromKey : successor(getNode(fromKey)).key,
+ maxKey);
}
- public Collection<SV> values()
+ public Collection<V> values()
{
if (this.values == null)
// Create an AbstractCollection with custom implementations of those
@@ -1762,7 +1868,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
return SubMap.this.size();
}
- public Iterator<SV> iterator()
+ public Iterator<V> iterator()
{
Node first = lowestGreaterThan(minKey, true);
Node max = lowestGreaterThan(maxKey, false);
@@ -1776,5 +1882,1439 @@ public class TreeMap<K, V> extends AbstractMap<K, V>
};
return this.values;
}
- } // class SubMap
+
+ private class KeySet
+ extends AbstractSet<K>
+ {
+ public int size()
+ {
+ return SubMap.this.size();
+ }
+
+ public Iterator<K> iterator()
+ {
+ Node first = lowestGreaterThan(minKey, true);
+ Node max = lowestGreaterThan(maxKey, false);
+ return new TreeIterator(KEYS, first, max);
+ }
+
+ public void clear()
+ {
+ SubMap.this.clear();
+ }
+
+ public boolean contains(Object o)
+ {
+ if (! keyInRange((K) o))
+ return false;
+ return getNode((K) o) != nil;
+ }
+
+ public boolean remove(Object o)
+ {
+ if (! keyInRange((K) o))
+ return false;
+ Node n = getNode((K) o);
+ if (n != nil)
+ {
+ removeNode(n);
+ return true;
+ }
+ return false;
+ }
+
+ } // class SubMap.KeySet
+
+ private final class NavigableKeySet
+ extends KeySet
+ implements NavigableSet<K>
+ {
+
+ public K ceiling(K k)
+ {
+ return SubMap.this.ceilingKey(k);
+ }
+
+ public Comparator<? super K> comparator()
+ {
+ return comparator;
+ }
+
+ public Iterator<K> descendingIterator()
+ {
+ return descendingSet().iterator();
+ }
+
+ public NavigableSet<K> descendingSet()
+ {
+ return new DescendingSet(this);
+ }
+
+ public K first()
+ {
+ return SubMap.this.firstKey();
+ }
+
+ public K floor(K k)
+ {
+ return SubMap.this.floorKey(k);
+ }
+
+ public SortedSet<K> headSet(K to)
+ {
+ return headSet(to, false);
+ }
+
+ public NavigableSet<K> headSet(K to, boolean inclusive)
+ {
+ return SubMap.this.headMap(to, inclusive).navigableKeySet();
+ }
+
+ public K higher(K k)
+ {
+ return SubMap.this.higherKey(k);
+ }
+
+ public K last()
+ {
+ return SubMap.this.lastKey();
+ }
+
+ public K lower(K k)
+ {
+ return SubMap.this.lowerKey(k);
+ }
+
+ public K pollFirst()
+ {
+ return SubMap.this.pollFirstEntry().getKey();
+ }
+
+ public K pollLast()
+ {
+ return SubMap.this.pollLastEntry().getKey();
+ }
+
+ public SortedSet<K> subSet(K from, K to)
+ {
+ return subSet(from, true, to, false);
+ }
+
+ public NavigableSet<K> subSet(K from, boolean fromInclusive,
+ K to, boolean toInclusive)
+ {
+ return SubMap.this.subMap(from, fromInclusive,
+ to, toInclusive).navigableKeySet();
+ }
+
+ public SortedSet<K> tailSet(K from)
+ {
+ return tailSet(from, true);
+ }
+
+ public NavigableSet<K> tailSet(K from, boolean inclusive)
+ {
+ return SubMap.this.tailMap(from, inclusive).navigableKeySet();
+ }
+
+ } // class SubMap.NavigableKeySet
+
+ /**
+ * Implementation of {@link #entrySet()}.
+ */
+ private class EntrySet
+ extends AbstractSet<Entry<K,V>>
+ {
+
+ public int size()
+ {
+ return SubMap.this.size();
+ }
+
+ public Iterator<Map.Entry<K,V>> iterator()
+ {
+ Node first = lowestGreaterThan(minKey, true);
+ Node max = lowestGreaterThan(maxKey, false);
+ return new TreeIterator(ENTRIES, first, max);
+ }
+
+ public void clear()
+ {
+ SubMap.this.clear();
+ }
+
+ public boolean contains(Object o)
+ {
+ if (! (o instanceof Map.Entry))
+ return false;
+ Map.Entry<K,V> me = (Map.Entry<K,V>) o;
+ K key = me.getKey();
+ if (! keyInRange(key))
+ return false;
+ Node<K,V> n = getNode(key);
+ return n != nil && AbstractSet.equals(me.getValue(), n.value);
+ }
+
+ public boolean remove(Object o)
+ {
+ if (! (o instanceof Map.Entry))
+ return false;
+ Map.Entry<K,V> me = (Map.Entry<K,V>) o;
+ K key = me.getKey();
+ if (! keyInRange(key))
+ return false;
+ Node<K,V> n = getNode(key);
+ if (n != nil && AbstractSet.equals(me.getValue(), n.value))
+ {
+ removeNode(n);
+ return true;
+ }
+ return false;
+ }
+ } // class SubMap.EntrySet
+
+ private final class NavigableEntrySet
+ extends EntrySet
+ implements NavigableSet<Entry<K,V>>
+ {
+
+ public Entry<K,V> ceiling(Entry<K,V> e)
+ {
+ return SubMap.this.ceilingEntry(e.getKey());
+ }
+
+ public Comparator<? super Entry<K,V>> comparator()
+ {
+ return new Comparator<Entry<K,V>>()
+ {
+ public int compare(Entry<K,V> t1, Entry<K,V> t2)
+ {
+ return comparator.compare(t1.getKey(), t2.getKey());
+ }
+ };
+ }
+
+ public Iterator<Entry<K,V>> descendingIterator()
+ {
+ return descendingSet().iterator();
+ }
+
+ public NavigableSet<Entry<K,V>> descendingSet()
+ {
+ return new DescendingSet(this);
+ }
+
+ public Entry<K,V> first()
+ {
+ return SubMap.this.firstEntry();
+ }
+
+ public Entry<K,V> floor(Entry<K,V> e)
+ {
+ return SubMap.this.floorEntry(e.getKey());
+ }
+
+ public SortedSet<Entry<K,V>> headSet(Entry<K,V> to)
+ {
+ return headSet(to, false);
+ }
+
+ public NavigableSet<Entry<K,V>> headSet(Entry<K,V> to, boolean inclusive)
+ {
+ return (NavigableSet<Entry<K,V>>)
+ SubMap.this.headMap(to.getKey(), inclusive).entrySet();
+ }
+
+ public Entry<K,V> higher(Entry<K,V> e)
+ {
+ return SubMap.this.higherEntry(e.getKey());
+ }
+
+ public Entry<K,V> last()
+ {
+ return SubMap.this.lastEntry();
+ }
+
+ public Entry<K,V> lower(Entry<K,V> e)
+ {
+ return SubMap.this.lowerEntry(e.getKey());
+ }
+
+ public Entry<K,V> pollFirst()
+ {
+ return SubMap.this.pollFirstEntry();
+ }
+
+ public Entry<K,V> pollLast()
+ {
+ return SubMap.this.pollLastEntry();
+ }
+
+ public SortedSet<Entry<K,V>> subSet(Entry<K,V> from, Entry<K,V> to)
+ {
+ return subSet(from, true, to, false);
+ }
+
+ public NavigableSet<Entry<K,V>> subSet(Entry<K,V> from, boolean fromInclusive,
+ Entry<K,V> to, boolean toInclusive)
+ {
+ return (NavigableSet<Entry<K,V>>)
+ SubMap.this.subMap(from.getKey(), fromInclusive,
+ to.getKey(), toInclusive).entrySet();
+ }
+
+ public SortedSet<Entry<K,V>> tailSet(Entry<K,V> from)
+ {
+ return tailSet(from, true);
+ }
+
+ public NavigableSet<Entry<K,V>> tailSet(Entry<K,V> from, boolean inclusive)
+ {
+ return (NavigableSet<Entry<K,V>>)
+ SubMap.this.tailMap(from.getKey(), inclusive).navigableKeySet();
+ }
+
+ } // class SubMap.NavigableEntrySet
+
+} // class SubMap
+
+ /**
+ * Returns the entry associated with the least or lowest key
+ * that is greater than or equal to the specified key, or
+ * <code>null</code> if there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the entry with the least key greater than or equal
+ * to the given key, or <code>null</code> if there is
+ * no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public Entry<K,V> ceilingEntry(K key)
+ {
+ Node<K,V> n = lowestGreaterThan(key, false);
+ return (n == nil) ? null : n;
+ }
+
+ /**
+ * Returns the the least or lowest key that is greater than
+ * or equal to the specified key, or <code>null</code> if
+ * there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the least key greater than or equal to the given key,
+ * or <code>null</code> if there is no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public K ceilingKey(K key)
+ {
+ Entry<K,V> e = ceilingEntry(key);
+ return (e == null) ? null : e.getKey();
+ }
+
+ /**
+ * Returns a reverse ordered {@link NavigableSet} view of this
+ * map's keys. The set is backed by the {@link TreeMap}, so changes
+ * in one show up in the other. The set supports element removal,
+ * but not element addition.
+ *
+ * @return a reverse ordered set view of the keys.
+ * @since 1.6
+ * @see #descendingMap()
+ */
+ public NavigableSet<K> descendingKeySet()
+ {
+ return descendingMap().navigableKeySet();
+ }
+
+ /**
+ * Returns a view of the map in reverse order. The descending map
+ * is backed by the original map, so that changes affect both maps.
+ * Any changes occurring to either map while an iteration is taking
+ * place (with the exception of a {@link Iterator#remove()} operation)
+ * result in undefined behaviour from the iteration. The ordering
+ * of the descending map is the same as for a map with a
+ * {@link Comparator} given by {@link Collections#reverseOrder()},
+ * and calling {@link #descendingMap()} on the descending map itself
+ * results in a view equivalent to the original map.
+ *
+ * @return a reverse order view of the map.
+ * @since 1.6
+ */
+ public NavigableMap<K,V> descendingMap()
+ {
+ if (descendingMap == null)
+ descendingMap = new DescendingMap<K,V>(this);
+ return descendingMap;
+ }
+
+ /**
+ * Returns the entry associated with the least or lowest key
+ * in the map, or <code>null</code> if the map is empty.
+ *
+ * @return the lowest entry, or <code>null</code> if the map
+ * is empty.
+ * @since 1.6
+ */
+ public Entry<K,V> firstEntry()
+ {
+ Node<K,V> n = firstNode();
+ return (n == nil) ? null : n;
+ }
+
+ /**
+ * Returns the entry associated with the greatest or highest key
+ * that is less than or equal to the specified key, or
+ * <code>null</code> if there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the entry with the greatest key less than or equal
+ * to the given key, or <code>null</code> if there is
+ * no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public Entry<K,V> floorEntry(K key)
+ {
+ Node<K,V> n = highestLessThan(key, true);
+ return (n == nil) ? null : n;
+ }
+
+ /**
+ * Returns the the greatest or highest key that is less than
+ * or equal to the specified key, or <code>null</code> if
+ * there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the greatest key less than or equal to the given key,
+ * or <code>null</code> if there is no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public K floorKey(K key)
+ {
+ Entry<K,V> e = floorEntry(key);
+ return (e == null) ? null : e.getKey();
+ }
+
+ /**
+ * Returns the entry associated with the least or lowest key
+ * that is strictly greater than the specified key, or
+ * <code>null</code> if there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the entry with the least key greater than
+ * the given key, or <code>null</code> if there is
+ * no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public Entry<K,V> higherEntry(K key)
+ {
+ Node<K,V> n = lowestGreaterThan(key, false, false);
+ return (n == nil) ? null : n;
+ }
+
+ /**
+ * Returns the the least or lowest key that is strictly
+ * greater than the specified key, or <code>null</code> if
+ * there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the least key greater than the given key,
+ * or <code>null</code> if there is no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public K higherKey(K key)
+ {
+ Entry<K,V> e = higherEntry(key);
+ return (e == null) ? null : e.getKey();
+ }
+
+ /**
+ * Returns the entry associated with the greatest or highest key
+ * in the map, or <code>null</code> if the map is empty.
+ *
+ * @return the highest entry, or <code>null</code> if the map
+ * is empty.
+ * @since 1.6
+ */
+ public Entry<K,V> lastEntry()
+ {
+ Node<K,V> n = lastNode();
+ return (n == nil) ? null : n;
+ }
+
+ /**
+ * Returns the entry associated with the greatest or highest key
+ * that is strictly less than the specified key, or
+ * <code>null</code> if there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the entry with the greatest key less than
+ * the given key, or <code>null</code> if there is
+ * no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public Entry<K,V> lowerEntry(K key)
+ {
+ Node<K,V> n = highestLessThan(key);
+ return (n == nil) ? null : n;
+ }
+
+ /**
+ * Returns the the greatest or highest key that is strictly
+ * less than the specified key, or <code>null</code> if
+ * there is no such key.
+ *
+ * @param key the key relative to the returned entry.
+ * @return the greatest key less than the given key,
+ * or <code>null</code> if there is no such key.
+ * @throws ClassCastException if the specified key can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the key is <code>null</code>
+ * and this map either uses natural
+ * ordering or a comparator that does
+ * not permit null keys.
+ * @since 1.6
+ */
+ public K lowerKey(K key)
+ {
+ Entry<K,V> e = lowerEntry(key);
+ return (e == null) ? null : e.getKey();
+ }
+
+ /**
+ * Returns a {@link NavigableSet} view of this map's keys. The set is
+ * backed by the {@link TreeMap}, so changes in one show up in the other.
+ * Any changes occurring to either while an iteration is taking
+ * place (with the exception of a {@link Iterator#remove()} operation)
+ * result in undefined behaviour from the iteration. The ordering
+ * The set supports element removal, but not element addition.
+ *
+ * @return a {@link NavigableSet} view of the keys.
+ * @since 1.6
+ */
+ public NavigableSet<K> navigableKeySet()
+ {
+ if (nKeys == null)
+ nKeys = new NavigableKeySet();
+ return nKeys;
+ }
+
+ /**
+ * Removes and returns the entry associated with the least
+ * or lowest key in the map, or <code>null</code> if the map
+ * is empty.
+ *
+ * @return the removed first entry, or <code>null</code> if the
+ * map is empty.
+ * @since 1.6
+ */
+ public Entry<K,V> pollFirstEntry()
+ {
+ Entry<K,V> e = firstEntry();
+ if (e != null)
+ removeNode((Node<K,V>)e);
+ return e;
+ }
+
+ /**
+ * Removes and returns the entry associated with the greatest
+ * or highest key in the map, or <code>null</code> if the map
+ * is empty.
+ *
+ * @return the removed last entry, or <code>null</code> if the
+ * map is empty.
+ * @since 1.6
+ */
+ public Entry<K,V> pollLastEntry()
+ {
+ Entry<K,V> e = lastEntry();
+ if (e != null)
+ removeNode((Node<K,V>)e);
+ return e;
+ }
+
+ /**
+ * Implementation of {@link #descendingMap()} and associated
+ * derivatives. This class provides a view of the
+ * original backing map in reverse order, and throws
+ * {@link IllegalArgumentException} for attempts to
+ * access beyond that range.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+ private static final class DescendingMap<DK,DV>
+ implements NavigableMap<DK,DV>
+ {
+
+ /**
+ * The cache for {@link #entrySet()}.
+ */
+ private Set<Map.Entry<DK,DV>> entries;
+
+ /**
+ * The cache for {@link #keySet()}.
+ */
+ private Set<DK> keys;
+
+ /**
+ * The cache for {@link #navigableKeySet()}.
+ */
+ private NavigableSet<DK> nKeys;
+
+ /**
+ * The cache for {@link #values()}.
+ */
+ private Collection<DV> values;
+
+ /**
+ * The backing {@link NavigableMap}.
+ */
+ private NavigableMap<DK,DV> map;
+
+ /**
+ * Create a {@link DescendingMap} around the specified
+ * map.
+ *
+ * @param map the map to wrap.
+ */
+ public DescendingMap(NavigableMap<DK,DV> map)
+ {
+ this.map = map;
+ }
+
+ public Map.Entry<DK,DV> ceilingEntry(DK key)
+ {
+ return map.floorEntry(key);
+ }
+
+ public DK ceilingKey(DK key)
+ {
+ return map.floorKey(key);
+ }
+
+ public void clear()
+ {
+ map.clear();
+ }
+
+ public Comparator<? super DK> comparator()
+ {
+ return Collections.reverseOrder(map.comparator());
+ }
+
+ public boolean containsKey(Object o)
+ {
+ return map.containsKey(o);
+ }
+
+ public boolean containsValue(Object o)
+ {
+ return map.containsValue(o);
+ }
+
+ public NavigableSet<DK> descendingKeySet()
+ {
+ return descendingMap().navigableKeySet();
+ }
+
+ public NavigableMap<DK,DV> descendingMap()
+ {
+ return map;
+ }
+
+ public Set<Entry<DK,DV>> entrySet()
+ {
+ if (entries == null)
+ entries =
+ new DescendingSet<Entry<DK,DV>>((NavigableSet<Entry<DK,DV>>)
+ map.entrySet());
+ return entries;
+ }
+
+ public boolean equals(Object o)
+ {
+ return map.equals(o);
+ }
+
+ public Entry<DK,DV> firstEntry()
+ {
+ return map.lastEntry();
+ }
+
+ public DK firstKey()
+ {
+ return map.lastKey();
+ }
+
+ public Entry<DK,DV> floorEntry(DK key)
+ {
+ return map.ceilingEntry(key);
+ }
+
+ public DK floorKey(DK key)
+ {
+ return map.ceilingKey(key);
+ }
+
+ public DV get(Object key)
+ {
+ return map.get(key);
+ }
+
+ public int hashCode()
+ {
+ return map.hashCode();
+ }
+
+ public SortedMap<DK,DV> headMap(DK toKey)
+ {
+ return headMap(toKey, false);
+ }
+
+ public NavigableMap<DK,DV> headMap(DK toKey, boolean inclusive)
+ {
+ return new DescendingMap(map.tailMap(toKey, inclusive));
+ }
+
+ public Entry<DK,DV> higherEntry(DK key)
+ {
+ return map.lowerEntry(key);
+ }
+
+ public DK higherKey(DK key)
+ {
+ return map.lowerKey(key);
+ }
+
+ public Set<DK> keySet()
+ {
+ if (keys == null)
+ keys = new DescendingSet<DK>(map.navigableKeySet());
+ return keys;
+ }
+
+ public boolean isEmpty()
+ {
+ return map.isEmpty();
+ }
+
+ public Entry<DK,DV> lastEntry()
+ {
+ return map.firstEntry();
+ }
+
+ public DK lastKey()
+ {
+ return map.firstKey();
+ }
+
+ public Entry<DK,DV> lowerEntry(DK key)
+ {
+ return map.higherEntry(key);
+ }
+
+ public DK lowerKey(DK key)
+ {
+ return map.higherKey(key);
+ }
+
+ public NavigableSet<DK> navigableKeySet()
+ {
+ if (nKeys == null)
+ nKeys = new DescendingSet<DK>(map.navigableKeySet());
+ return nKeys;
+ }
+
+ public Entry<DK,DV> pollFirstEntry()
+ {
+ return pollLastEntry();
+ }
+
+ public Entry<DK,DV> pollLastEntry()
+ {
+ return pollFirstEntry();
+ }
+
+ public DV put(DK key, DV value)
+ {
+ return map.put(key, value);
+ }
+
+ public void putAll(Map<? extends DK, ? extends DV> m)
+ {
+ map.putAll(m);
+ }
+
+ public DV remove(Object key)
+ {
+ return map.remove(key);
+ }
+
+ public int size()
+ {
+ return map.size();
+ }
+
+ public SortedMap<DK,DV> subMap(DK fromKey, DK toKey)
+ {
+ return subMap(fromKey, true, toKey, false);
+ }
+
+ public NavigableMap<DK,DV> subMap(DK fromKey, boolean fromInclusive,
+ DK toKey, boolean toInclusive)
+ {
+ return new DescendingMap(map.subMap(fromKey, fromInclusive,
+ toKey, toInclusive));
+ }
+
+ public SortedMap<DK,DV> tailMap(DK fromKey)
+ {
+ return tailMap(fromKey, true);
+ }
+
+ public NavigableMap<DK,DV> tailMap(DK fromKey, boolean inclusive)
+ {
+ return new DescendingMap(map.headMap(fromKey, inclusive));
+ }
+
+ public String toString()
+ {
+ StringBuilder r = new StringBuilder("{");
+ final Iterator<Entry<DK,DV>> it = entrySet().iterator();
+ while (it.hasNext())
+ {
+ final Entry<DK,DV> e = it.next();
+ r.append(e.getKey());
+ r.append('=');
+ r.append(e.getValue());
+ r.append(", ");
+ }
+ r.replace(r.length() - 2, r.length(), "}");
+ return r.toString();
+ }
+
+ public Collection<DV> values()
+ {
+ if (values == null)
+ // Create an AbstractCollection with custom implementations of those
+ // methods that can be overriden easily and efficiently.
+ values = new AbstractCollection()
+ {
+ public int size()
+ {
+ return size();
+ }
+
+ public Iterator<DV> iterator()
+ {
+ return new Iterator<DV>()
+ {
+ /** The last Entry returned by a next() call. */
+ private Entry<DK,DV> last;
+
+ /** The next entry that should be returned by next(). */
+ private Entry<DK,DV> next = firstEntry();
+
+ public boolean hasNext()
+ {
+ return next != null;
+ }
+
+ public DV next()
+ {
+ if (next == null)
+ throw new NoSuchElementException();
+ last = next;
+ next = higherEntry(last.getKey());
+
+ return last.getValue();
+ }
+
+ public void remove()
+ {
+ if (last == null)
+ throw new IllegalStateException();
+
+ DescendingMap.this.remove(last.getKey());
+ last = null;
+ }
+ };
+ }
+
+ public void clear()
+ {
+ clear();
+ }
+ };
+ return values;
+ }
+
+ } // class DescendingMap
+
+ /**
+ * Implementation of {@link #keySet()}.
+ */
+ private class KeySet
+ extends AbstractSet<K>
+ {
+
+ public int size()
+ {
+ return size;
+ }
+
+ public Iterator<K> iterator()
+ {
+ return new TreeIterator(KEYS);
+ }
+
+ public void clear()
+ {
+ TreeMap.this.clear();
+ }
+
+ public boolean contains(Object o)
+ {
+ return containsKey(o);
+ }
+
+ public boolean remove(Object key)
+ {
+ Node<K,V> n = getNode((K) key);
+ if (n == nil)
+ return false;
+ removeNode(n);
+ return true;
+ }
+ } // class KeySet
+
+ /**
+ * Implementation of {@link #navigableKeySet()}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+ private final class NavigableKeySet
+ extends KeySet
+ implements NavigableSet<K>
+ {
+
+ public K ceiling(K k)
+ {
+ return ceilingKey(k);
+ }
+
+ public Comparator<? super K> comparator()
+ {
+ return comparator;
+ }
+
+ public Iterator<K> descendingIterator()
+ {
+ return descendingSet().iterator();
+ }
+
+ public NavigableSet<K> descendingSet()
+ {
+ return new DescendingSet<K>(this);
+ }
+
+ public K first()
+ {
+ return firstKey();
+ }
+
+ public K floor(K k)
+ {
+ return floorKey(k);
+ }
+
+ public SortedSet<K> headSet(K to)
+ {
+ return headSet(to, false);
+ }
+
+ public NavigableSet<K> headSet(K to, boolean inclusive)
+ {
+ return headMap(to, inclusive).navigableKeySet();
+ }
+
+ public K higher(K k)
+ {
+ return higherKey(k);
+ }
+
+ public K last()
+ {
+ return lastKey();
+ }
+
+ public K lower(K k)
+ {
+ return lowerKey(k);
+ }
+
+ public K pollFirst()
+ {
+ return pollFirstEntry().getKey();
+ }
+
+ public K pollLast()
+ {
+ return pollLastEntry().getKey();
+ }
+
+ public SortedSet<K> subSet(K from, K to)
+ {
+ return subSet(from, true, to, false);
+ }
+
+ public NavigableSet<K> subSet(K from, boolean fromInclusive,
+ K to, boolean toInclusive)
+ {
+ return subMap(from, fromInclusive,
+ to, toInclusive).navigableKeySet();
+ }
+
+ public SortedSet<K> tailSet(K from)
+ {
+ return tailSet(from, true);
+ }
+
+ public NavigableSet<K> tailSet(K from, boolean inclusive)
+ {
+ return tailMap(from, inclusive).navigableKeySet();
+ }
+
+
+ } // class NavigableKeySet
+
+ /**
+ * Implementation of {@link #descendingSet()} and associated
+ * derivatives. This class provides a view of the
+ * original backing set in reverse order, and throws
+ * {@link IllegalArgumentException} for attempts to
+ * access beyond that range.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+ private static final class DescendingSet<D>
+ implements NavigableSet<D>
+ {
+
+ /**
+ * The backing {@link NavigableSet}.
+ */
+ private NavigableSet<D> set;
+
+ /**
+ * Create a {@link DescendingSet} around the specified
+ * set.
+ *
+ * @param map the set to wrap.
+ */
+ public DescendingSet(NavigableSet<D> set)
+ {
+ this.set = set;
+ }
+
+ public boolean add(D e)
+ {
+ return set.add(e);
+ }
+
+ public boolean addAll(Collection<? extends D> c)
+ {
+ return set.addAll(c);
+ }
+
+ public D ceiling(D e)
+ {
+ return set.floor(e);
+ }
+
+ public void clear()
+ {
+ set.clear();
+ }
+
+ public Comparator<? super D> comparator()
+ {
+ return Collections.reverseOrder(set.comparator());
+ }
+
+ public boolean contains(Object o)
+ {
+ return set.contains(o);
+ }
+
+ public boolean containsAll(Collection<?> c)
+ {
+ return set.containsAll(c);
+ }
+
+ public Iterator<D> descendingIterator()
+ {
+ return descendingSet().iterator();
+ }
+
+ public NavigableSet<D> descendingSet()
+ {
+ return set;
+ }
+
+ public boolean equals(Object o)
+ {
+ return set.equals(o);
+ }
+
+ public D first()
+ {
+ return set.last();
+ }
+
+ public D floor(D e)
+ {
+ return set.ceiling(e);
+ }
+
+ public int hashCode()
+ {
+ return set.hashCode();
+ }
+
+ public SortedSet<D> headSet(D to)
+ {
+ return headSet(to, false);
+ }
+
+ public NavigableSet<D> headSet(D to, boolean inclusive)
+ {
+ return new DescendingSet(set.tailSet(to, inclusive));
+ }
+
+ public D higher(D e)
+ {
+ return set.lower(e);
+ }
+
+ public boolean isEmpty()
+ {
+ return set.isEmpty();
+ }
+
+ public Iterator<D> iterator()
+ {
+ return new Iterator<D>()
+ {
+
+ /** The last element returned by a next() call. */
+ private D last;
+
+ /** The next element that should be returned by next(). */
+ private D next = first();
+
+ public boolean hasNext()
+ {
+ return next != null;
+ }
+
+ public D next()
+ {
+ if (next == null)
+ throw new NoSuchElementException();
+ last = next;
+ next = higher(last);
+
+ return last;
+ }
+
+ public void remove()
+ {
+ if (last == null)
+ throw new IllegalStateException();
+
+ DescendingSet.this.remove(last);
+ last = null;
+ }
+ };
+ }
+
+ public D last()
+ {
+ return set.first();
+ }
+
+ public D lower(D e)
+ {
+ return set.higher(e);
+ }
+
+ public D pollFirst()
+ {
+ return set.pollLast();
+ }
+
+ public D pollLast()
+ {
+ return set.pollFirst();
+ }
+
+ public boolean remove(Object o)
+ {
+ return set.remove(o);
+ }
+
+ public boolean removeAll(Collection<?> c)
+ {
+ return set.removeAll(c);
+ }
+
+ public boolean retainAll(Collection<?> c)
+ {
+ return set.retainAll(c);
+ }
+
+ public int size()
+ {
+ return set.size();
+ }
+
+ public SortedSet<D> subSet(D from, D to)
+ {
+ return subSet(from, true, to, false);
+ }
+
+ public NavigableSet<D> subSet(D from, boolean fromInclusive,
+ D to, boolean toInclusive)
+ {
+ return new DescendingSet(set.subSet(from, fromInclusive,
+ to, toInclusive));
+ }
+
+ public SortedSet<D> tailSet(D from)
+ {
+ return tailSet(from, true);
+ }
+
+ public NavigableSet<D> tailSet(D from, boolean inclusive)
+ {
+ return new DescendingSet(set.headSet(from, inclusive));
+ }
+
+ public Object[] toArray()
+ {
+ D[] array = (D[]) set.toArray();
+ Arrays.sort(array, comparator());
+ return array;
+ }
+
+ public <T> T[] toArray(T[] a)
+ {
+ T[] array = set.toArray(a);
+ Arrays.sort(array, (Comparator<? super T>) comparator());
+ return array;
+ }
+
+ public String toString()
+ {
+ StringBuilder r = new StringBuilder("[");
+ final Iterator<D> it = iterator();
+ while (it.hasNext())
+ {
+ final D o = it.next();
+ if (o == this)
+ r.append("<this>");
+ else
+ r.append(o);
+ r.append(", ");
+ }
+ r.replace(r.length() - 2, r.length(), "]");
+ return r.toString();
+ }
+
+ } // class DescendingSet
+
+ private class EntrySet
+ extends AbstractSet<Entry<K,V>>
+ {
+ public int size()
+ {
+ return size;
+ }
+
+ public Iterator<Map.Entry<K,V>> iterator()
+ {
+ return new TreeIterator(ENTRIES);
+ }
+
+ public void clear()
+ {
+ TreeMap.this.clear();
+ }
+
+ public boolean contains(Object o)
+ {
+ if (! (o instanceof Map.Entry))
+ return false;
+ Map.Entry<K,V> me = (Map.Entry<K,V>) o;
+ Node<K,V> n = getNode(me.getKey());
+ return n != nil && AbstractSet.equals(me.getValue(), n.value);
+ }
+
+ public boolean remove(Object o)
+ {
+ if (! (o instanceof Map.Entry))
+ return false;
+ Map.Entry<K,V> me = (Map.Entry<K,V>) o;
+ Node<K,V> n = getNode(me.getKey());
+ if (n != nil && AbstractSet.equals(me.getValue(), n.value))
+ {
+ removeNode(n);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private final class NavigableEntrySet
+ extends EntrySet
+ implements NavigableSet<Entry<K,V>>
+ {
+
+ public Entry<K,V> ceiling(Entry<K,V> e)
+ {
+ return ceilingEntry(e.getKey());
+ }
+
+ public Comparator<? super Entry<K,V>> comparator()
+ {
+ return new Comparator<Entry<K,V>>()
+ {
+ public int compare(Entry<K,V> t1, Entry<K,V> t2)
+ {
+ return comparator.compare(t1.getKey(), t2.getKey());
+ }
+ };
+ }
+
+ public Iterator<Entry<K,V>> descendingIterator()
+ {
+ return descendingSet().iterator();
+ }
+
+ public NavigableSet<Entry<K,V>> descendingSet()
+ {
+ return new DescendingSet(this);
+ }
+
+ public Entry<K,V> first()
+ {
+ return firstEntry();
+ }
+
+ public Entry<K,V> floor(Entry<K,V> e)
+ {
+ return floorEntry(e.getKey());
+ }
+
+ public SortedSet<Entry<K,V>> headSet(Entry<K,V> to)
+ {
+ return headSet(to, false);
+ }
+
+ public NavigableSet<Entry<K,V>> headSet(Entry<K,V> to, boolean inclusive)
+ {
+ return (NavigableSet<Entry<K,V>>) headMap(to.getKey(), inclusive).entrySet();
+ }
+
+ public Entry<K,V> higher(Entry<K,V> e)
+ {
+ return higherEntry(e.getKey());
+ }
+
+ public Entry<K,V> last()
+ {
+ return lastEntry();
+ }
+
+ public Entry<K,V> lower(Entry<K,V> e)
+ {
+ return lowerEntry(e.getKey());
+ }
+
+ public Entry<K,V> pollFirst()
+ {
+ return pollFirstEntry();
+ }
+
+ public Entry<K,V> pollLast()
+ {
+ return pollLastEntry();
+ }
+
+ public SortedSet<Entry<K,V>> subSet(Entry<K,V> from, Entry<K,V> to)
+ {
+ return subSet(from, true, to, false);
+ }
+
+ public NavigableSet<Entry<K,V>> subSet(Entry<K,V> from, boolean fromInclusive,
+ Entry<K,V> to, boolean toInclusive)
+ {
+ return (NavigableSet<Entry<K,V>>) subMap(from.getKey(), fromInclusive,
+ to.getKey(), toInclusive).entrySet();
+ }
+
+ public SortedSet<Entry<K,V>> tailSet(Entry<K,V> from)
+ {
+ return tailSet(from, true);
+ }
+
+ public NavigableSet<Entry<K,V>> tailSet(Entry<K,V> from, boolean inclusive)
+ {
+ return (NavigableSet<Entry<K,V>>) tailMap(from.getKey(), inclusive).navigableKeySet();
+ }
+
+ } // class NavigableEntrySet
+
} // class TreeMap
diff --git a/libjava/classpath/java/util/TreeSet.java b/libjava/classpath/java/util/TreeSet.java
index 2851e4a5a8f..572cda6425c 100644
--- a/libjava/classpath/java/util/TreeSet.java
+++ b/libjava/classpath/java/util/TreeSet.java
@@ -79,10 +79,10 @@ import java.io.Serializable;
* @see Collections#synchronizedSortedSet(SortedSet)
* @see TreeMap
* @since 1.2
- * @status updated to 1.4
+ * @status updated to 1.6
*/
public class TreeSet<T> extends AbstractSet<T>
- implements SortedSet<T>, Cloneable, Serializable
+ implements NavigableSet<T>, Cloneable, Serializable
{
/**
* Compatible with JDK 1.2.
@@ -90,11 +90,11 @@ public class TreeSet<T> extends AbstractSet<T>
private static final long serialVersionUID = -2479143000061671589L;
/**
- * The SortedMap which backs this Set.
+ * The NavigableMap which backs this Set.
*/
// Not final because of readObject. This will always be one of TreeMap or
// TreeMap.SubMap, which both extend AbstractMap.
- private transient SortedMap<T, String> map;
+ private transient NavigableMap<T, String> map;
/**
* Construct a new TreeSet whose backing TreeMap using the "natural"
@@ -163,7 +163,7 @@ public class TreeSet<T> extends AbstractSet<T>
*
* @param backingMap the submap
*/
- private TreeSet(SortedMap<T,String> backingMap)
+ private TreeSet(NavigableMap<T,String> backingMap)
{
map = backingMap;
}
@@ -220,7 +220,7 @@ public class TreeSet<T> extends AbstractSet<T>
{
copy = (TreeSet<T>) super.clone();
// Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts.
- copy.map = (SortedMap<T, String>) ((AbstractMap<T, String>) map).clone();
+ copy.map = (NavigableMap<T, String>) ((AbstractMap<T, String>) map).clone();
}
catch (CloneNotSupportedException x)
{
@@ -269,7 +269,9 @@ public class TreeSet<T> extends AbstractSet<T>
* in one appear in the other. The subset will throw an
* {@link IllegalArgumentException} for any attempt to access or add an
* element beyond the specified cutoff. The returned set does not include
- * the endpoint; if you want inclusion, pass the successor element.
+ * the endpoint; if you want inclusion, pass the successor element or
+ * call {@link #headSet(T,boolean)}. This call is equivalent to
+ * <code>headSet(to, false)</code>.
*
* @param to the (exclusive) cutoff point
* @return a view of the set less than the cutoff
@@ -280,7 +282,28 @@ public class TreeSet<T> extends AbstractSet<T>
*/
public SortedSet<T> headSet(T to)
{
- return new TreeSet<T>(map.headMap(to));
+ return headSet(to, false);
+ }
+
+ /**
+ * Returns a view of this Set including all elements less than
+ * (or equal to, if <code>inclusive</code> is true) <code>to</code>.
+ * The returned set is backed by the original, so changes
+ * in one appear in the other. The subset will throw an
+ * {@link IllegalArgumentException} for any attempt to access or add an
+ * element beyond the specified cutoff.
+ *
+ * @param to the cutoff point
+ * @param inclusive true if <code>to</code> should be included.
+ * @return a view of the set for the specified range.
+ * @throws ClassCastException if <code>to</code> is not compatible with
+ * the comparator (or is not Comparable, for natural ordering)
+ * @throws NullPointerException if to is null, but the comparator does not
+ * tolerate null elements
+ */
+ public NavigableSet<T> headSet(T to, boolean inclusive)
+ {
+ return new TreeSet<T>(map.headMap(to, inclusive));
}
/**
@@ -345,7 +368,9 @@ public class TreeSet<T> extends AbstractSet<T>
* the other. The subset will throw an {@link IllegalArgumentException}
* for any attempt to access or add an element beyond the specified cutoffs.
* The returned set includes the low endpoint but not the high; if you want
- * to reverse this behavior on either end, pass in the successor element.
+ * to reverse this behavior on either end, pass in the successor element
+ * or call {@link #subSet(T,boolean,T,boolean)}. This is equivalent to
+ * calling <code>subSet(from,true,to,false)</code>.
*
* @param from the (inclusive) low cutoff point
* @param to the (exclusive) high cutoff point
@@ -358,7 +383,33 @@ public class TreeSet<T> extends AbstractSet<T>
*/
public SortedSet<T> subSet(T from, T to)
{
- return new TreeSet<T>(map.subMap(from, to));
+ return subSet(from, true, to, false);
+ }
+
+ /**
+ * Returns a view of this Set including all elements greater than (or equal to,
+ * if <code>fromInclusive</code> is true</code> <code>from</code> and less than
+ * (or equal to, if <code>toInclusive</code> is true) <code>to</code>.
+ * The returned set is backed by the original, so changes in one appear in
+ * the other. The subset will throw an {@link IllegalArgumentException}
+ * for any attempt to access or add an element beyond the specified cutoffs.
+ *
+ * @param from the low cutoff point
+ * @param fromInclusive true if <code>from</code> should be included.
+ * @param to the high cutoff point
+ * @param toInclusive true if <code>to</code> should be included.
+ * @return a view of the set for the specified range.
+ * @throws ClassCastException if either cutoff is not compatible with
+ * the comparator (or is not Comparable, for natural ordering)
+ * @throws NullPointerException if from or to is null, but the comparator
+ * does not tolerate null elements
+ * @throws IllegalArgumentException if from is greater than to
+ */
+ public NavigableSet<T> subSet(T from, boolean fromInclusive,
+ T to, boolean toInclusive)
+ {
+ return new TreeSet<T>(map.subMap(from, fromInclusive,
+ to, toInclusive));
}
/**
@@ -367,7 +418,9 @@ public class TreeSet<T> extends AbstractSet<T>
* changes in one appear in the other. The subset will throw an
* {@link IllegalArgumentException} for any attempt to access or add an
* element beyond the specified cutoff. The returned set includes the
- * endpoint; if you want to exclude it, pass in the successor element.
+ * endpoint; if you want to exclude it, pass in the successor element
+ * or call {@link #tailSet(T,boolean)}. This is equivalent to calling
+ * <code>tailSet(from, true)</code>.
*
* @param from the (inclusive) low cutoff point
* @return a view of the set above the cutoff
@@ -378,7 +431,27 @@ public class TreeSet<T> extends AbstractSet<T>
*/
public SortedSet<T> tailSet(T from)
{
- return new TreeSet<T>(map.tailMap(from));
+ return tailSet(from, true);
+ }
+
+ /**
+ * Returns a view of this Set including all elements greater (or equal to,
+ * if <code>inclusive</code> is true) <code>from</code>. The returned set
+ * is backed by the original, so changes in one appear in the other. The
+ * subset will throw an {@link IllegalArgumentException} for any attempt
+ * to access or add an element beyond the specified cutoff.
+ *
+ * @param from the low cutoff point.
+ * @param inclusive true if <code>from</code> should be included.
+ * @return a view of the set for the specified range.
+ * @throws ClassCastException if <code>from</code> is not compatible with
+ * the comparator (or is not Comparable, for natural ordering)
+ * @throws NullPointerException if from is null, but the comparator
+ * does not tolerate null elements
+ */
+ public NavigableSet<T> tailSet(T from, boolean inclusive)
+ {
+ return new TreeSet<T>(map.tailMap(from, inclusive));
}
/**
@@ -418,4 +491,151 @@ public class TreeSet<T> extends AbstractSet<T>
map = new TreeMap<T, String>(comparator);
((TreeMap<T, String>) map).putFromObjStream(s, size, false);
}
+
+ /**
+ * Returns the least or lowest element in the set greater than or
+ * equal to the given element, or <code>null</code> if there is
+ * no such element.
+ *
+ * @param e the element relative to the returned element.
+ * @return the least element greater than or equal
+ * to the given element, or <code>null</code> if there is
+ * no such element.
+ * @throws ClassCastException if the specified element can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the element is <code>null</code>
+ * and this set either uses natural
+ * ordering or a comparator that does
+ * not permit null elements.
+ * @since 1.6
+ */
+ public T ceiling(T e)
+ {
+ return map.ceilingKey(e);
+ }
+
+ /**
+ * Returns an iterator over the elements of this set in descending
+ * order. This is equivalent to calling
+ * <code>descendingSet().iterator()</code>.
+ *
+ * @return an iterator over the elements in descending order.
+ * @since 1.6
+ */
+ public Iterator<T> descendingIterator()
+ {
+ return descendingSet().iterator();
+ }
+
+ /**
+ * Returns a view of the set in reverse order. The descending set
+ * is backed by the original set, so that changes affect both sets.
+ * Any changes occurring to either set while an iteration is taking
+ * place (with the exception of a {@link Iterator#remove()} operation)
+ * result in undefined behaviour from the iteration. The ordering
+ * of the descending set is the same as for a set with a
+ * {@link Comparator} given by {@link Collections#reverseOrder()},
+ * and calling {@link #descendingSet()} on the descending set itself
+ * results in a view equivalent to the original set.
+ *
+ * @return a reverse order view of the set.
+ * @since 1.6
+ */
+ public NavigableSet<T> descendingSet()
+ {
+ return map.descendingKeySet();
+ }
+
+ /**
+ * Returns the greatest or highest element in the set less than or
+ * equal to the given element, or <code>null</code> if there is
+ * no such element.
+ *
+ * @param e the element relative to the returned element.
+ * @return the greatest element less than or equal
+ * to the given element, or <code>null</code> if there is
+ * no such element.
+ * @throws ClassCastException if the specified element can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the element is <code>null</code>
+ * and this set either uses natural
+ * ordering or a comparator that does
+ * not permit null elements.
+ * @since 1.6
+ */
+ public T floor(T e)
+ {
+ return map.floorKey(e);
+ }
+
+ /**
+ * Returns the least or lowest element in the set strictly greater
+ * than the given element, or <code>null</code> if there is
+ * no such element.
+ *
+ * @param e the element relative to the returned element.
+ * @return the least element greater than
+ * the given element, or <code>null</code> if there is
+ * no such element.
+ * @throws ClassCastException if the specified element can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the element is <code>null</code>
+ * and this set either uses natural
+ * ordering or a comparator that does
+ * not permit null elements.
+ * @since 1.6
+ */
+ public T higher(T e)
+ {
+ return map.higherKey(e);
+ }
+
+ /**
+ * Returns the greatest or highest element in the set strictly less
+ * than the given element, or <code>null</code> if there is
+ * no such element.
+ *
+ * @param e the element relative to the returned element.
+ * @return the greatest element less than
+ * the given element, or <code>null</code> if there is
+ * no such element.
+ * @throws ClassCastException if the specified element can not
+ * be compared with those in the map.
+ * @throws NullPointerException if the element is <code>null</code>
+ * and this set either uses natural
+ * ordering or a comparator that does
+ * not permit null elements.
+ * @since 1.6
+ */
+ public T lower(T e)
+ {
+ return map.lowerKey(e);
+ }
+
+ /**
+ * Removes and returns the least or lowest element in the set,
+ * or <code>null</code> if the map is empty.
+ *
+ * @return the removed first element, or <code>null</code> if the
+ * map is empty.
+ * @since 1.6
+ */
+ public T pollFirst()
+ {
+ return map.pollFirstEntry().getKey();
+ }
+
+ /**
+ * Removes and returns the greatest or highest element in the set,
+ * or <code>null</code> if the map is empty.
+ *
+ * @return the removed last element, or <code>null</code> if the
+ * map is empty.
+ * @since 1.6
+ */
+ public T pollLast()
+ {
+ return map.pollLastEntry().getKey();
+ }
+
}
diff --git a/libjava/classpath/java/util/class-dependencies.conf b/libjava/classpath/java/util/class-dependencies.conf
deleted file mode 100644
index 39f96062744..00000000000
--- a/libjava/classpath/java/util/class-dependencies.conf
+++ /dev/null
@@ -1,78 +0,0 @@
-# This property file contains dependencies of classes, methods, and
-# field on other methods or classes.
-#
-# Syntax:
-#
-# <used>: <needed 1> [... <needed N>]
-#
-# means that when <used> is included, <needed 1> (... <needed N>) must
-# be included as well.
-#
-# <needed X> and <used> are of the form
-#
-# <class.methodOrField(signature)>
-#
-# or just
-#
-# <class>
-#
-# Within dependencies, variables can be used. A variable is defined as
-# follows:
-#
-# {variable}: value1 value2 ... value<n>
-#
-# variables can be used on the right side of dependencies as follows:
-#
-# <used>: com.bla.blu.{variable}.Class.m()V
-#
-# The use of the variable will expand to <n> dependencies of the form
-#
-# <used>: com.bla.blu.value1.Class.m()V
-# <used>: com.bla.blu.value2.Class.m()V
-# ...
-# <used>: com.bla.blu.value<n>.Class.m()V
-#
-# Variables can be redefined when building a system to select the
-# required support for features like encodings, protocols, etc.
-#
-# Hints:
-#
-# - For methods and fields, the signature is mandatory. For
-# specification, please see the Java Virtual Machine Specification by
-# SUN. Unlike in the spec, field signatures (types) are in brackets.
-#
-# - Package names must be separated by '/' (and not '.'). E.g.,
-# java/lang/Class (this is necessary, because the '.' is used to
-# separate method or field names from classes)
-#
-# - In case <needed> refers to a class, only the class itself will be
-# included in the resulting binary, NOT necessarily all its methods
-# and fields. If you want to refer to all methods and fields, you can
-# write class.* as an abbreviation.
-#
-# - Abbreviations for packages are also possible: my/package/* means all
-# methods and fields of all classes in my/package.
-#
-# - A line with a trailing '\' continues in the next line.
-
-
-# All calendars supported are loaded via java/util/Calendar.getBundle or
-# java/util/GregorianCalendar.getBundle from class
-# gnu/java/locale/Calendar_{locale_id}
-#
-# This introduces a dependency for the localized calendars. To allow an easy
-# selection and addition of locales, the library variable {calendar_locales}
-# can be set to the set of supported calendar locales.
-#
-
-{calendar_locales}: de en nl
-
-java/util/Calendar.getBundle(Ljava/util/Locale;)Ljava/util/ResourceBundle;: \
- gnu/java/locale/Calendar.* \
- gnu/java/locale/Calendar_{calendar_locales}.*
-
-java/util/GregorianCalendar.getBundle(Ljava/util/Locale;)Ljava/util/ResourceBundle;: \
- gnu/java/locale/Calendar.* \
- gnu/java/locale/Calendar_{calendar_locales}.*
-
-# end of file
diff --git a/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java b/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java
index 5ef37d94916..48c017f50fa 100644
--- a/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java
@@ -349,7 +349,8 @@ public class CopyOnWriteArrayList<E> extends AbstractList<E> implements
{
E[] data = this.data;
E[] newData = (E[]) new Object[data.length - 1];
- System.arraycopy(data, 0, newData, 0, index - 1);
+ if (index > 0)
+ System.arraycopy(data, 0, newData, 0, index - 1);
System.arraycopy(data, index + 1, newData, index,
data.length - index - 1);
E r = data[index];
diff --git a/libjava/classpath/java/util/logging/LogManager.java b/libjava/classpath/java/util/logging/LogManager.java
index fbc0fe78abf..6daf3dbd9eb 100644
--- a/libjava/classpath/java/util/logging/LogManager.java
+++ b/libjava/classpath/java/util/logging/LogManager.java
@@ -1,6 +1,6 @@
/* LogManager.java -- a class for maintaining Loggers and managing
configuration properties
- Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -446,8 +446,8 @@ public class LogManager
Iterator<WeakReference<Logger>> iter = loggers.values().iterator();
while (iter.hasNext())
- for (WeakReference<Logger> ref : loggers.values())
{
+ WeakReference<Logger> ref;
Logger logger;
ref = iter.next();
@@ -559,13 +559,21 @@ public class LogManager
if ("handlers".equals(key))
{
- StringTokenizer tokenizer = new StringTokenizer(value);
+ // In Java 5 and earlier this was specified to be
+ // whitespace-separated, but in reality it also accepted
+ // commas (tomcat relied on this), and in Java 6 the
+ // documentation was updated to fit the implementation.
+ StringTokenizer tokenizer = new StringTokenizer(value,
+ " \t\n\r\f,");
while (tokenizer.hasMoreTokens())
{
String handlerName = tokenizer.nextToken();
Handler handler = (Handler)
createInstance(handlerName, Handler.class, key);
- Logger.root.addHandler(handler);
+ // Tomcat also relies on the implementation ignoring
+ // items in 'handlers' which are not class names.
+ if (handler != null)
+ Logger.root.addHandler(handler);
}
}
diff --git a/libjava/classpath/java/util/logging/Logger.java b/libjava/classpath/java/util/logging/Logger.java
index 46588e542ee..01ef8f522b8 100644
--- a/libjava/classpath/java/util/logging/Logger.java
+++ b/libjava/classpath/java/util/logging/Logger.java
@@ -1,5 +1,5 @@
/* Logger.java -- a class for logging messages
- Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -276,8 +276,8 @@ public class Logger
LogManager lm = LogManager.getLogManager();
Logger result;
- /* Throw NullPointerException if name is null. */
- name.getClass();
+ if (name == null)
+ throw new NullPointerException();
/* Without synchronized(lm), it could happen that another thread
* would create a logger between our calls to getLogger and
@@ -1013,8 +1013,8 @@ public class Logger
public synchronized void addHandler(Handler handler)
throws SecurityException
{
- /* Throw a new NullPointerException if handler is null. */
- handler.getClass();
+ if (handler == null)
+ throw new NullPointerException();
/* An application is allowed to control an anonymous logger
* without having the permission to control the logging
@@ -1057,8 +1057,8 @@ public class Logger
if (!anonymous)
LogManager.getLogManager().checkAccess();
- /* Throw a new NullPointerException if handler is null. */
- handler.getClass();
+ if (handler == null)
+ throw new NullPointerException();
handlerList.remove(handler);
handlers = getHandlers();
@@ -1166,8 +1166,8 @@ public class Logger
*/
public synchronized void setParent(Logger parent)
{
- /* Throw a new NullPointerException if parent is null. */
- parent.getClass();
+ if (parent == null)
+ throw new NullPointerException();
if (this == root)
throw new IllegalArgumentException(
diff --git a/libjava/classpath/java/util/prefs/AbstractPreferences.java b/libjava/classpath/java/util/prefs/AbstractPreferences.java
index e676dc3105c..f3a62e6980d 100644
--- a/libjava/classpath/java/util/prefs/AbstractPreferences.java
+++ b/libjava/classpath/java/util/prefs/AbstractPreferences.java
@@ -45,6 +45,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
@@ -97,17 +98,18 @@ public abstract class AbstractPreferences extends Preferences {
* accessed by earlier <code>getChild()</code> or <code>childSpi()</code>
* invocations and that have not been removed.
*/
- private HashMap childCache = new HashMap();
+ private HashMap<String, AbstractPreferences> childCache
+ = new HashMap<String, AbstractPreferences>();
/**
* A list of all the registered NodeChangeListener objects.
*/
- private ArrayList nodeListeners;
+ private ArrayList<NodeChangeListener> nodeListeners;
/**
* A list of all the registered PreferenceChangeListener objects.
*/
- private ArrayList preferenceListeners;
+ private ArrayList<PreferenceChangeListener> preferenceListeners;
// constructor
@@ -202,7 +204,8 @@ public abstract class AbstractPreferences extends Preferences {
*/
protected final AbstractPreferences[] cachedChildren()
{
- return (AbstractPreferences[]) childCache.values().toArray();
+ Collection<AbstractPreferences> vals = childCache.values();
+ return vals.toArray(new AbstractPreferences[vals.size()]);
}
/**
@@ -228,7 +231,7 @@ public abstract class AbstractPreferences extends Preferences {
if (isRemoved())
throw new IllegalStateException("Node removed");
- TreeSet childrenNames = new TreeSet();
+ TreeSet<String> childrenNames = new TreeSet<String>();
// First get all cached node names
childrenNames.addAll(childCache.keySet());
@@ -1165,7 +1168,7 @@ public abstract class AbstractPreferences extends Preferences {
if (listener == null)
throw new NullPointerException("listener is null");
if (nodeListeners == null)
- nodeListeners = new ArrayList();
+ nodeListeners = new ArrayList<NodeChangeListener>();
nodeListeners.add(listener);
}
}
@@ -1184,7 +1187,7 @@ public abstract class AbstractPreferences extends Preferences {
if (listener == null)
throw new NullPointerException("listener is null");
if (preferenceListeners == null)
- preferenceListeners = new ArrayList();
+ preferenceListeners = new ArrayList<PreferenceChangeListener>();
preferenceListeners.add(listener);
}
}
diff --git a/libjava/classpath/java/util/prefs/Preferences.java b/libjava/classpath/java/util/prefs/Preferences.java
index e53e4fc7938..e8cdda8ed0a 100644
--- a/libjava/classpath/java/util/prefs/Preferences.java
+++ b/libjava/classpath/java/util/prefs/Preferences.java
@@ -183,9 +183,9 @@ public abstract class Preferences {
// Get the factory
if (factory == null) {
// Caller might not have enough permissions
- factory = (PreferencesFactory) AccessController.doPrivileged(
- new PrivilegedAction() {
- public Object run() {
+ factory = AccessController.doPrivileged(
+ new PrivilegedAction<PreferencesFactory>() {
+ public PreferencesFactory run() {
PreferencesFactory pf = null;
String className = System.getProperty
("java.util.prefs.PreferencesFactory");
diff --git a/libjava/classpath/java/util/regex/Pattern.java b/libjava/classpath/java/util/regex/Pattern.java
index d716fa4e62d..217ce0862a9 100644
--- a/libjava/classpath/java/util/regex/Pattern.java
+++ b/libjava/classpath/java/util/regex/Pattern.java
@@ -1,5 +1,5 @@
/* Pattern.java -- Compiled regular expression ready to be applied.
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -246,7 +246,7 @@ public final class Pattern implements Serializable
{
String t = input.subSequence(start, input.length()).toString();
if ("".equals(t) && limit == 0)
- ; // Don't add.
+ { /* Don't add. */ }
else
list.add(t);
}
@@ -260,4 +260,14 @@ public final class Pattern implements Serializable
{
return regex;
}
+
+ /**
+ * Return the regular expression used to construct this object.
+ * @specnote Prior to JDK 1.5 this method had a different behavior
+ * @since 1.5
+ */
+ public String toString()
+ {
+ return regex;
+ }
}
diff --git a/libjava/classpath/java/util/spi/CurrencyNameProvider.java b/libjava/classpath/java/util/spi/CurrencyNameProvider.java
new file mode 100644
index 00000000000..14fae4d87a3
--- /dev/null
+++ b/libjava/classpath/java/util/spi/CurrencyNameProvider.java
@@ -0,0 +1,100 @@
+/* CurrencyNameProvider.java -- Providers of localized currency symbols
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.spi;
+
+import java.util.Locale;
+
+/**
+ * A {@link CurrencyNameProvider} provides localized
+ * versions of the symbols that represent a particular
+ * currency. Note that currency symbols are regarded
+ * as names, and thus a <code>null</code> value may
+ * be returned, which should be treated as a lack of
+ * support for the specified {@link Locale}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class CurrencyNameProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link CurrencyNameProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected CurrencyNameProvider()
+ {
+ }
+
+ /**
+ * <p>
+ * This method returns the symbol which precedes or follows a
+ * value in this particular currency. The returned value is
+ * the symbol used to denote the currency in the specified locale.
+ * </p>
+ * <p>
+ * For example, a supplied locale may specify a different symbol
+ * for the currency, due to conflicts with its own currency.
+ * This would be the case with the American currency, the dollar.
+ * Locales that also use a dollar-based currency (e.g. Canada, Australia)
+ * need to differentiate the American dollar using 'US$' rather than '$'.
+ * So, supplying one of these locales to <code>getSymbol()</code> would
+ * return this value, rather than the standard '$'.
+ * </p>
+ * <p>
+ * In cases where there is no such symbol for a particular currency,
+ * <code>null</code> should be returned.
+ * </p>
+ *
+ * @param currencyCode the ISO 4217 currency code, consisting
+ * of three uppercase letters from 'A' to 'Z'
+ * @param locale the locale to express the symbol in.
+ * @return the currency symbol, or <code>null</code> if one is
+ * unavailable.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the currency code is
+ * not in the correct format
+ * or the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.util.Currency#getSymbol(java.util.Locale)
+ */
+ public abstract String getSymbol(String currencyCode, Locale locale);
+
+}
diff --git a/libjava/classpath/java/util/spi/LocaleNameProvider.java b/libjava/classpath/java/util/spi/LocaleNameProvider.java
new file mode 100644
index 00000000000..dfd2e4cbc0a
--- /dev/null
+++ b/libjava/classpath/java/util/spi/LocaleNameProvider.java
@@ -0,0 +1,135 @@
+/* LocaleNameProvider.java -- Providers of localized locale names
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.spi;
+
+import java.util.Locale;
+
+/**
+ * A {@link LocaleNameProvider} provides localized
+ * versions of the names that represent a particular
+ * locale. Note that a <code>null</code> value may
+ * be returned, which should be treated as a lack of
+ * support for the specified {@link Locale}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class LocaleNameProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link LocaleNameProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected LocaleNameProvider()
+ {
+ }
+
+ /**
+ * Returns the localized name for the specified ISO 3166
+ * country in the supplied {@link java.util.Locale}.
+ * For example, if the country code is <code>"DE"</code>,
+ * this method will return <code>"Germany"</code> for
+ * {@link Locale.ENGLISH} but <code>"Deutschland"</code>
+ * for {@link Locale.GERMANY}. If the name of the country
+ * in the given locale is not supported, <code>null</code>
+ * is returned.
+ *
+ * @param countryCode the ISO 3166 country code, consisting
+ * of two uppercase letters from 'A' to 'Z'
+ * @param locale the locale to express the country in.
+ * @return the country name, or <code>null</code> if one is
+ * not available.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the country code is
+ * not in the correct format
+ * or the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.util.Locale#getDisplayCountry(java.util.Locale)
+ */
+ public abstract String getDisplayCountry(String countryCode,
+ Locale locale);
+
+ /**
+ * Returns the localized name for the specified ISO 639
+ * language in the supplied {@link java.util.Locale}.
+ * For example, if the language code is <code>"de"</code>,
+ * this method will return <code>"German"</code> for
+ * {@link Locale.ENGLISH} but <code>"Deutsch"</code>
+ * for {@link Locale.GERMANY}. If the name of the language
+ * in the given locale is not supported, <code>null</code>
+ * is returned.
+ *
+ * @param langCode the ISO 639 language code, consisting
+ * of two lowercase letters from 'a' to 'z'
+ * @param locale the locale to express the language in.
+ * @return the country name, or <code>null</code> if one is
+ * not available.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the language code is
+ * not in the correct format
+ * or the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.util.Locale#getDisplayLanguage(java.util.Locale)
+ */
+ public abstract String getDisplayLanguage(String langCode,
+ Locale locale);
+
+ /**
+ * Returns the localized name for the specified variant
+ * in the supplied {@link java.util.Locale}. If the name
+ * of the variant in the given locale is not supported,
+ * <code>null</code> is returned.
+ *
+ * @param variant the variant.
+ * @param locale the locale to express the variant in.
+ * @return the localized variant, or <code>null</code> if one is
+ * not available.
+ * @throws NullPointerException if the locale is null.
+ * @throws IllegalArgumentException if the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.util.Locale#getDisplayVariant(java.util.Locale)
+ */
+ public abstract String getDisplayVariant(String variant,
+ Locale locale);
+
+}
diff --git a/libjava/classpath/java/util/spi/LocaleServiceProvider.java b/libjava/classpath/java/util/spi/LocaleServiceProvider.java
new file mode 100644
index 00000000000..bb5b68527fc
--- /dev/null
+++ b/libjava/classpath/java/util/spi/LocaleServiceProvider.java
@@ -0,0 +1,125 @@
+/* LocaleServiceProvider.java -- Superclass of locale SPIs
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.spi;
+
+import java.util.Locale;
+
+/**
+ * <p>
+ * This is the superclass of all the {@link Locale} service
+ * provider interfaces or SPIs. The locale SPIs are used
+ * to allow for the provision of additional support for
+ * locale-specific data. The runtime environment has its
+ * own collection of locale data, but these interfaces allow
+ * this to be extended by external classes.
+ * </p>
+ * <p>
+ * Service providers are created as concrete implementations
+ * of these interfaces, and accessed using the extension
+ * mechanism, realised by {@link ServiceLoader}. When a factory
+ * method of one of the locale-specific classes (such as
+ * {@link java.text.DateFormatSymbols} or {@link java.util.Currency})
+ * is called, the runtime environment is first asked to
+ * provide data for the specified locale. If the runtime
+ * environment fails to provide this, then the offer is
+ * made to service providers which implement the appropriate
+ * interface.
+ * </p>
+ * <p>
+ * Each provider implements the method specified by this
+ * class, {@link #getAvailableLocales()}. This method is
+ * called first to determine whether the provider will be of
+ * any use in providing data for the specified locale. If
+ * a provider is found to be capable, then a more specific
+ * method appropriate to the class requiring the data will
+ * be called. In the case of {@link java.text.DateFormatSymbols},
+ * this would be
+ * {@link java.text.spi.DateFormatSymbols#getInstance(Locale)}.
+ * </p>
+ * <p>
+ * If neither a service provider nor the runtime environment
+ * itself can fulfill the request, a fallback procedure is
+ * engaged. The locale is modified by applying the first
+ * applicable rule:
+ * </p>
+ * <ol>
+ * <li>If the variant contains a <code>'_'</code>, then
+ * this and everything following it is trimmed.</li>
+ * <li>If the variant is non-empty, it is converted to
+ * an empty string.</li>
+ * <li>If the country is non-empty, it is converted to
+ * an empty string.</li>
+ * <li>If the language is non-empty, it is converted to
+ * an empty string.</li>
+ * </ol>
+ * <p>
+ * The modified locale is then used to start the same
+ * process again. The root locale (@link java.util.Locale#ROOT}
+ * must be supported by the runtime environment in order
+ * to terminate this cycle.
+ * </p>
+ * <p>
+ * Note that any names returned by the providers may
+ * be <code>null</code>. Returning a <code>null</code>
+ * name is considered equivalent to not supporting a
+ * particular locale.
+ * </p>
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link LocaleServiceProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected LocaleServiceProvider()
+ {
+ }
+
+ /**
+ * Returns an array of {@link Locale} instances,
+ * for which the provider can supply localized data.
+ *
+ * @return an array of supported locales.
+ */
+ public abstract Locale[] getAvailableLocales();
+
+}
diff --git a/libjava/classpath/java/util/spi/TimeZoneNameProvider.java b/libjava/classpath/java/util/spi/TimeZoneNameProvider.java
new file mode 100644
index 00000000000..2815670574c
--- /dev/null
+++ b/libjava/classpath/java/util/spi/TimeZoneNameProvider.java
@@ -0,0 +1,97 @@
+/* TimeZoneNameProvider.java -- Providers of localized currency symbols
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.spi;
+
+import java.util.Locale;
+
+/**
+ * A {@link TimeZoneNameProvider} provides localized
+ * versions of the names that represent a particular
+ * timezone. A <code>null</code> value may
+ * be returned, which should be treated as a lack of
+ * support for the specified {@link Locale}. The names
+ * from this class are also used by
+ * {@link DateFormatSymbols#getZoneStrings()}.
+ *
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.6
+ */
+public abstract class TimeZoneNameProvider
+ extends LocaleServiceProvider
+{
+
+ /**
+ * Constructs a new {@link TimeZoneNameProvider}.
+ * Provided for implicit invocation by subclasses.
+ */
+ protected TimeZoneNameProvider()
+ {
+ }
+
+ /**
+ * Returns a name for the specified time zone identifier
+ * localized to the supplied {@link java.util.Locale}.
+ * The time zone identifier is either <code>"GMT"</code>
+ * or one of the identifiers from the public domain "tz
+ * database" found at <a href="ftp://elsie.nci.nih.gov/pub/">
+ * ftp://elsie.nci.nih.gov/pub</a>. Note that a translated
+ * name for the daylight savings time variant should be returned,
+ * even if the timezone has not observed daylight savings
+ * time in the past. If the name of the timezone
+ * in the given locale is not supported, <code>null</code>
+ * is returned.
+ *
+ * @param id a time zone identifier.
+ * @param daylight true if the daylight savings time variant
+ * should be returned.
+ * @param style either {@link java.util.TimeZone.LONG} or
+ * {@link java.util.TimeZone.SHORT}
+ * @param locale the locale to express the timezone in.
+ * @return the localized time zone name, or <code>null</code>
+ * if one is not available.
+ * @throws NullPointerException if the identifer or locale is null.
+ * @throws IllegalArgumentException if the style is invalid
+ * or the locale is not one
+ * returned by
+ * {@link getAvailableLocales()}
+ * @see java.util.TimeZone#getDisplayName(boolean,int,java.util.Locale)
+ */
+ public abstract String getDisplayName(String id, boolean daylight,
+ int style, Locale locale);
+
+}
diff --git a/libjava/classpath/java/util/spi/package.html b/libjava/classpath/java/util/spi/package.html
new file mode 100644
index 00000000000..1abdeb8b4ad
--- /dev/null
+++ b/libjava/classpath/java/util/spi/package.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in java.util.spi package.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - java.util.spi</title></head>
+
+<body>
+
+<p>
+A series of service provider interfaces for use by the
+classes in <code>java.util</code>.
+</p>
+<p><span style="font-weight: bold;">Since</span>: 1.6</p>
+</body>
+</html>
diff --git a/libjava/classpath/java/util/zip/DeflaterEngine.java b/libjava/classpath/java/util/zip/DeflaterEngine.java
index 51587165e7c..38a82d8b77b 100644
--- a/libjava/classpath/java/util/zip/DeflaterEngine.java
+++ b/libjava/classpath/java/util/zip/DeflaterEngine.java
@@ -377,7 +377,8 @@ class DeflaterEngine implements DeflaterConstants
&& window[++scan] == window[++match]
&& window[++scan] == window[++match]
&& window[++scan] == window[++match]
- && scan < strend);
+ && scan < strend)
+ ;
if (scan > best_end) {
// if (DeflaterConstants.DEBUGGING && ins_h == 0)
diff --git a/libjava/classpath/java/util/zip/ZipInputStream.java b/libjava/classpath/java/util/zip/ZipInputStream.java
index 4539828c2b0..df44bb3e808 100644
--- a/libjava/classpath/java/util/zip/ZipInputStream.java
+++ b/libjava/classpath/java/util/zip/ZipInputStream.java
@@ -238,6 +238,7 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
byte[] tmp = new byte[2048];
while (read(tmp) > 0)
;
+
/* read will close this entry */
return;
}