From 2d8cf20d0d5ca6b1fbdefc22229d4b7cf1497ede Mon Sep 17 00:00:00 2001
From: mark
Date: Tue, 17 Jan 2006 18:09:40 +0000
Subject: Imported GNU Classpath 0.20 * Makefile.am
(AM_CPPFLAGS): Add classpath/include. *
java/nio/charset/spi/CharsetProvider.java: New override file. *
java/security/Security.java: Likewise. * sources.am: Regenerated.
* Makefile.in: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@109831 138bc75d-0d04-0410-961f-82ee72b054a4
---
libjava/classpath/java/awt/BorderLayout.java | 2 +-
libjava/classpath/java/awt/Component.java | 42 +-
libjava/classpath/java/awt/Container.java | 59 +-
libjava/classpath/java/awt/GridBagLayout.java | 24 +-
.../java/awt/datatransfer/DataFlavor.java | 1704 ++++++++++----------
.../java/awt/datatransfer/SystemFlavorMap.java | 292 +++-
.../java/beans/DefaultPersistenceDelegate.java | 194 +++
libjava/classpath/java/beans/Encoder.java | 463 ++++++
.../classpath/java/beans/EventSetDescriptor.java | 1173 +++++++++-----
libjava/classpath/java/beans/Expression.java | 81 +-
.../java/beans/IndexedPropertyChangeEvent.java | 81 +
libjava/classpath/java/beans/Introspector.java | 204 ++-
.../classpath/java/beans/PersistenceDelegate.java | 91 ++
.../java/beans/PropertyChangeSupport.java | 52 +
libjava/classpath/java/beans/Statement.java | 165 +-
libjava/classpath/java/beans/XMLEncoder.java | 265 +++
libjava/classpath/java/io/File.java | 9 +-
libjava/classpath/java/io/InputStreamReader.java | 4 +
libjava/classpath/java/io/ObjectInputStream.java | 1 -
libjava/classpath/java/io/ObjectOutputStream.java | 5 +
libjava/classpath/java/io/ObjectStreamClass.java | 31 +
libjava/classpath/java/io/OutputStreamWriter.java | 4 +
libjava/classpath/java/io/PrintStream.java | 9 +-
libjava/classpath/java/io/RandomAccessFile.java | 47 +-
libjava/classpath/java/io/StreamTokenizer.java | 6 +
libjava/classpath/java/lang/Character.java | 11 +-
libjava/classpath/java/lang/Class.java | 8 +-
libjava/classpath/java/lang/Double.java | 75 +
libjava/classpath/java/lang/Float.java | 77 +
.../java/lang/InheritableThreadLocal.java | 13 +-
libjava/classpath/java/lang/SecurityManager.java | 15 +-
libjava/classpath/java/lang/StackTraceElement.java | 22 +-
libjava/classpath/java/lang/String.java | 16 +-
libjava/classpath/java/lang/Thread.java | 6 +-
libjava/classpath/java/lang/ThreadLocal.java | 23 +-
libjava/classpath/java/net/DatagramSocket.java | 7 +-
libjava/classpath/java/net/InetAddress.java | 139 +-
libjava/classpath/java/net/URL.java | 9 +-
libjava/classpath/java/nio/charset/Charset.java | 2 +
.../java/nio/charset/spi/CharsetProvider.java | 8 +-
libjava/classpath/java/security/MessageDigest.java | 5 +-
libjava/classpath/java/security/Security.java | 26 +-
libjava/classpath/java/text/Bidi.java | 78 +
libjava/classpath/java/text/DecimalFormat.java | 4 +-
libjava/classpath/java/util/AbstractMap.java | 4 +-
libjava/classpath/java/util/ArrayList.java | 2 +-
libjava/classpath/java/util/Collections.java | 8 +-
libjava/classpath/java/util/Hashtable.java | 232 ++-
libjava/classpath/java/util/Properties.java | 226 +--
libjava/classpath/java/util/StringTokenizer.java | 3 +-
libjava/classpath/java/util/WeakHashMap.java | 6 +-
.../classpath/java/util/logging/XMLFormatter.java | 2 +-
libjava/classpath/java/util/regex/Pattern.java | 5 +-
53 files changed, 4030 insertions(+), 2010 deletions(-)
create mode 100644 libjava/classpath/java/beans/DefaultPersistenceDelegate.java
create mode 100644 libjava/classpath/java/beans/Encoder.java
create mode 100644 libjava/classpath/java/beans/IndexedPropertyChangeEvent.java
create mode 100644 libjava/classpath/java/beans/PersistenceDelegate.java
create mode 100644 libjava/classpath/java/beans/XMLEncoder.java
create mode 100644 libjava/classpath/java/text/Bidi.java
(limited to 'libjava/classpath/java')
diff --git a/libjava/classpath/java/awt/BorderLayout.java b/libjava/classpath/java/awt/BorderLayout.java
index 1b67c01cfcb..7c8c582a96b 100644
--- a/libjava/classpath/java/awt/BorderLayout.java
+++ b/libjava/classpath/java/awt/BorderLayout.java
@@ -415,7 +415,7 @@ public class BorderLayout implements LayoutManager2, java.io.Serializable
*/
public Dimension maximumLayoutSize(Container target)
{
- return calcSize(target, MAX);
+ return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
diff --git a/libjava/classpath/java/awt/Component.java b/libjava/classpath/java/awt/Component.java
index ec03d631dcf..bd22ea3c984 100644
--- a/libjava/classpath/java/awt/Component.java
+++ b/libjava/classpath/java/awt/Component.java
@@ -1038,14 +1038,10 @@ public abstract class Component
if ((c != null) && c.equals(background))
return;
- // If c is null, inherit from closest ancestor whose bg is set.
- if (c == null && parent != null)
- c = parent.getBackground();
- if (peer != null && c != null)
- peer.setBackground(c);
-
Color previous = background;
background = c;
+ if (peer != null && c != null)
+ peer.setBackground(c);
firePropertyChange("background", previous, c);
}
@@ -2642,7 +2638,7 @@ public abstract class Component
{
mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, listener);
if (mouseMotionListener != null)
- enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+ enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
/**
@@ -2775,10 +2771,19 @@ public abstract class Component
}
/**
- * Returns all registered EventListers of the given listenerType.
+ * Returns all registered {@link EventListener}s of the given
+ *
- *
+ *
+ * If this flavor supports the charset parameter, it must be equivalent to
+ *
+ * If this flavor does not support the charset parameter, its
+ * representation must be
+ * See
+ * The present implementation of this method returns the specified MIME
+ * type
+ * The present implementation of this method returns the MIME type
+ *
+ * If the specified native is previously unknown to the data transfer
+ * subsystem, and that native has been properly encoded, then invoking
+ * this method will establish a mapping in both directions between the
+ * specified native and a DataFlavor whose MIME type is a decoded
+ * version of the native.
+ */
public List getFlavorsForNative (String nat)
{
throw new Error ("Not implemented");
@@ -165,5 +270,160 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
{
throw new Error ("Not implemented");
}
+
+ /**
+ * Adds a mapping from a single
+ * If the array contains several elements that reference equal
+ *
+ * It is recommended that client code not reset mappings established by the
+ * data transfer subsystem. This method should only be used for
+ * application-level mappings.
+ *
+ * @param flavor the
+ * If the array contains several elements that reference equal
+ *
+ * It is recommended that client code not reset mappings established by the
+ * data transfer subsystem. This method should only be used for
+ * application-level mappings.
+ *
+ * @param nativeStr the The implementation reads the mentioned properties from the Bean
+ * instance and applies it in the given order to a corresponding
+ * constructor.
+ * Note: Throws a
+ * Note: Silently ignores PersistenceDelegates for Array types and primitive
+ * wrapper classes.
+ *
+ * Note: Although this method is not declared
+ * Note: The Note: If
+ * Note: If you call this method not from within an object instantiation and
+ * initialization sequence it will be silently ignored.
+ *
+ * Note: If you call this method not from within an object instantiation and
+ * initialization sequence it will be silently ignored.
+ * Immutable objects always have to be instantiated instead of
+ * modifying an existing instance.
- **
- ** The methods have these constraints on them:
- **
- **
- ** There are also various design patterns associated with some of the methods
- ** of construction. Those are explained in more detail in the appropriate
- ** constructors.
- **
- ** Documentation Convention: for proper
- ** Internalization of Beans inside an RAD tool, sometimes there
- ** are two names for a property or method: a programmatic, or
- ** locale-independent name, which can be used anywhere, and a
- ** localized, display name, for ease of use. In the
- ** documentation I will specify different String values as
- ** either programmatic or localized to
- ** make this distinction clear.
- **
- ** @author John Keiser
- ** @since JDK1.1
- ** @version 1.1.0, 31 May 1998
- **/
-
-public class EventSetDescriptor extends FeatureDescriptor {
- private Method addListenerMethod;
- private Method removeListenerMethod;
- private Class listenerType;
- private MethodDescriptor[] listenerMethodDescriptors;
- private Method[] listenerMethods;
-
- private boolean unicast;
- private boolean inDefaultEventSet = true;
-
- /** Create a new EventSetDescriptor.
- ** This version of the constructor enforces the rules imposed on the methods
- ** described at the top of this class, as well as searching for:
- **
- **
- ** @param eventSourceClass the class containing the add and remove listener methods.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu).
- ** @param listenerType the class containing the event firing methods.
- ** @param listenerMethodNames the names of the even firing methods.
- ** @param addListenerMethodName the name of the add listener method.
- ** @param removeListenerMethodName the name of the remove listener method.
- ** @exception IntrospectionException if listenerType is not an EventListener
- ** or if methods are not found or are invalid.
- **/
- public EventSetDescriptor(Class eventSourceClass,
- String eventSetName,
- Class listenerType,
- String[] listenerMethodNames,
- String addListenerMethodName,
- String removeListenerMethodName) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- findMethods(eventSourceClass,listenerType,listenerMethodNames,addListenerMethodName,removeListenerMethodName,null);
- this.listenerType = listenerType;
- checkAddListenerUnicast();
- if(this.removeListenerMethod.getExceptionTypes().length > 0) {
- throw new IntrospectionException("Listener remove method throws exceptions.");
- }
- }
-
- /** Create a new EventSetDescriptor.
- ** This form of constructor allows you to explicitly say which methods do what, and
- ** no reflection is done by the EventSetDescriptor. The methods are, however,
- ** checked to ensure that they follow the rules set forth at the top of the class.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu).
- ** @param listenerType the class containing the listenerMethods.
- ** @param listenerMethods the event firing methods.
- ** @param addListenerMethod the add listener method.
- ** @param removeListenerMethod the remove listener method.
- ** @exception IntrospectionException if the listenerType is not an EventListener,
- ** or any of the methods are invalid.
- **/
- public EventSetDescriptor(String eventSetName,
- Class listenerType,
- Method[] listenerMethods,
- Method addListenerMethod,
- Method removeListenerMethod) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- this.listenerMethods = listenerMethods;
- this.addListenerMethod = addListenerMethod;
- this.removeListenerMethod = removeListenerMethod;
- this.listenerType = listenerType;
- checkMethods();
- checkAddListenerUnicast();
- if(this.removeListenerMethod.getExceptionTypes().length > 0) {
- throw new IntrospectionException("Listener remove method throws exceptions.");
- }
- }
-
- /** Create a new EventSetDescriptor.
- ** This form of constructor allows you to explicitly say which methods do what, and
- ** no reflection is done by the EventSetDescriptor. The methods are, however,
- ** checked to ensure that they follow the rules set forth at the top of the class.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu).
- ** @param listenerType the class containing the listenerMethods.
- ** @param listenerMethodDescriptors the event firing methods.
- ** @param addListenerMethod the add listener method.
- ** @param removeListenerMethod the remove listener method.
- ** @exception IntrospectionException if the listenerType is not an EventListener,
- ** or any of the methods are invalid.
- **/
- public EventSetDescriptor(String eventSetName,
- Class listenerType,
- MethodDescriptor[] listenerMethodDescriptors,
- Method addListenerMethod,
- Method removeListenerMethod) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- this.listenerMethodDescriptors = listenerMethodDescriptors;
- this.listenerMethods = new Method[listenerMethodDescriptors.length];
- for(int i=0;i
+ * The methods have these constraints on them:
+ *
+ * A final constraint is that event listener classes must extend from
+ * EventListener.
+ *
+ * There are also various design patterns associated with some of the methods
+ * of construction. Those are explained in more detail in the appropriate
+ * constructors.
+ *
+ * Documentation Convention: for proper Internalization of
+ * Beans inside an RAD tool, sometimes there are two names for a property or
+ * method: a programmatic, or locale-independent name, which can be used
+ * anywhere, and a localized, display name, for ease of use. In the
+ * documentation I will specify different String values as either
+ * programmatic or localized to make this distinction clear.
+ *
+ * @author John Keiser
+ * @author Robert Schuster (robertschuster@fsfe.org)
+ * @since 1.1
+ */
+
+public class EventSetDescriptor extends FeatureDescriptor
+{
+ private Method addListenerMethod;
+
+ private Method removeListenerMethod;
+
+ private Class listenerType;
+
+ private MethodDescriptor[] listenerMethodDescriptors;
+
+ private Method[] listenerMethods;
+
+ private Method getListenerMethod;
+
+ private boolean unicast;
+
+ private boolean inDefaultEventSet = true;
+
+ /**
+ * Creates a new This form of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ *
+ * This variant of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ *
+ * A valid GetListener method is public, flags no exceptions and has one
+ * argument which is of type
+ * Note: The validity of the return value of the GetListener method is not
+ * checked.
+ *
+ * This variant of the constructor allows you to specify the names of the
+ * methods and adds no new constraints on top of the rules already described
+ * at the top of the class.
+ *
+ * A valid GetListener method is public, flags no exceptions and has one
+ * argument which is of type
+ * Note: The validity of the return value of the GetListener method is not
+ * checked.
+ * This form of constructor allows you to explicitly say which methods
+ * do what, and no reflection is done by the This form of constructor allows you to explicitly say which methods do
+ * what, and no reflection is done by the An Expression captures the execution of an object method
+ * that returns a value. It stores an object, the method to call, and the arguments to pass to
+ * the method. While this class can generally be used to describe method calls it is
+ * part of the XML serialization API. You have three options: With {@link #USE_ALL_BEANINFO} the result is the same as
+ * {@link #getBeanInfo(Class)}. Calling the method with When the method is called with Note: Any unknown value for listenerType.
*
- * @param listenerType the class of listeners to filter
- * @return an array of registered listeners
+ * @param listenerType the class of listeners to filter (null
+ * not permitted).
+ *
+ * @return An array of registered listeners.
+ *
+ * @throws ClassCastException if listenerType does not implement
+ * the {@link EventListener} interface.
+ * @throws NullPointerException if listenerType is
+ * null.
+ *
* @see #getComponentListeners()
* @see #getFocusListeners()
* @see #getHierarchyListeners()
@@ -4786,7 +4791,12 @@ p * listenerType.
*
+ * @param listenerType the class of listeners to filter (null
+ * not permitted).
+ *
+ * @return An array of registered listeners.
+ *
+ * @throws ClassCastException if listenerType does not implement
+ * the {@link EventListener} interface.
+ * @throws NullPointerException if listenerType is
+ * null.
+ *
+ * @see #getContainerListeners()
+ *
* @since 1.3
*/
public EventListener[] getListeners(Class listenerType)
@@ -1094,7 +1099,7 @@ public class Container extends Component
{
if (!contains(x, y))
return null;
-
+
for (int i = 0; i < ncomponents; ++i)
{
// Ignore invisible children...
@@ -1117,7 +1122,8 @@ public class Container extends Component
}
//don't return transparent components with no MouseListeners
- if (this.getMouseListeners().length == 0)
+ if (getMouseListeners().length == 0
+ && getMouseMotionListeners().length == 0)
return null;
return this;
}
@@ -1625,30 +1631,19 @@ public class Container extends Component
Component comp)
{
Rectangle bounds = comp.getBounds();
- Rectangle oldClip = gfx.getClipBounds();
- if (oldClip == null)
- oldClip = bounds;
-
- Rectangle clip = oldClip.intersection(bounds);
- if (clip.isEmpty()) return;
+ if(!gfx.hitClip(bounds.x,bounds.y, bounds.width, bounds.height))
+ return;
- boolean clipped = false;
- boolean translated = false;
+ Graphics g2 = gfx.create(bounds.x, bounds.y, bounds.width,
+ bounds.height);
try
{
- gfx.setClip(clip.x, clip.y, clip.width, clip.height);
- clipped = true;
- gfx.translate(bounds.x, bounds.y);
- translated = true;
- visitor.visit(comp, gfx);
+ visitor.visit(comp, g2);
}
finally
{
- if (translated)
- gfx.translate (-bounds.x, -bounds.y);
- if (clipped)
- gfx.setClip (oldClip.x, oldClip.y, oldClip.width, oldClip.height);
+ g2.dispose();
}
}
@@ -2148,12 +2143,18 @@ class LightweightDispatcher implements Serializable
break;
}
- if (me.getID() == MouseEvent.MOUSE_PRESSED && modifiers > 0
+ if (me.getID() == MouseEvent.MOUSE_RELEASED
+ || me.getID() == MouseEvent.MOUSE_PRESSED && modifiers > 0
|| me.getID() == MouseEvent.MOUSE_DRAGGED)
{
// If any of the following events occur while a button is held down,
// they should be dispatched to the same component to which the
// original MOUSE_PRESSED event was dispatched:
+ // - MOUSE_RELEASED: This is important for correct dragging
+ // behaviour, otherwise the release goes to an arbitrary component
+ // outside of the dragged component. OTOH, if there is no mouse
+ // drag while the mouse is pressed, the component under the mouse
+ // is the same as the previously pressed component anyway.
// - MOUSE_PRESSED: another button pressed while the first is held
// down
// - MOUSE_DRAGGED
diff --git a/libjava/classpath/java/awt/GridBagLayout.java b/libjava/classpath/java/awt/GridBagLayout.java
index 083c0b7a7a3..714e080d7b2 100644
--- a/libjava/classpath/java/awt/GridBagLayout.java
+++ b/libjava/classpath/java/awt/GridBagLayout.java
@@ -341,11 +341,14 @@ public class GridBagLayout
GridBagLayoutInfo info = getLayoutInfo (parent, PREFERREDSIZE);
if (info.cols == 0 && info.rows == 0)
return;
- layoutInfo = info;
// DEBUG
- //dumpLayoutInfo (layoutInfo);
-
+ //dumpLayoutInfo (info);
+
+ // Calling setBounds on these components causes this layout to
+ // be invalidated, clearing the layout information cache,
+ // layoutInfo. So we wait until after this for loop to set
+ // layoutInfo.
for(int i = 0; i < components.length; i++)
{
Component component = components [i];
@@ -357,11 +360,11 @@ public class GridBagLayout
GridBagConstraints constraints =
lookupInternalConstraints(component);
- int cellx = sumIntArray(layoutInfo.colWidths, constraints.gridx);
- int celly = sumIntArray(layoutInfo.rowHeights, constraints.gridy);
- int cellw = sumIntArray(layoutInfo.colWidths,
+ int cellx = sumIntArray(info.colWidths, constraints.gridx);
+ int celly = sumIntArray(info.rowHeights, constraints.gridy);
+ int cellw = sumIntArray(info.colWidths,
constraints.gridx + constraints.gridwidth) - cellx;
- int cellh = sumIntArray(layoutInfo.rowHeights,
+ int cellh = sumIntArray(info.rowHeights,
constraints.gridy + constraints.gridheight) - celly;
Insets insets = constraints.insets;
@@ -438,11 +441,14 @@ public class GridBagLayout
break;
}
- component.setBounds(layoutInfo.pos_x + x, layoutInfo.pos_y + y, dim.width, dim.height);
+ component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, dim.height);
}
// DEBUG
- //dumpLayoutInfo (layoutInfo);
+ //dumpLayoutInfo (info);
+
+ // Cache layout information.
+ layoutInfo = getLayoutInfo (parent, PREFERREDSIZE);
}
/**
diff --git a/libjava/classpath/java/awt/datatransfer/DataFlavor.java b/libjava/classpath/java/awt/datatransfer/DataFlavor.java
index 38f415b7526..32bf4d6cf37 100644
--- a/libjava/classpath/java/awt/datatransfer/DataFlavor.java
+++ b/libjava/classpath/java/awt/datatransfer/DataFlavor.java
@@ -1,5 +1,5 @@
/* DataFlavor.java -- A type of data to transfer via the clipboard.
- Copyright (C) 1999, 2001, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2001, 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -49,6 +49,7 @@ import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
+import java.nio.charset.Charset;
import java.rmi.Remote;
/**
@@ -63,946 +64,818 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
// FIXME: Serialization: Need to write methods for.
-/**
- * This is the data flavor used for tranferring plain text. The MIME
- * type is "text/plain; charset=unicode". The representation class
- * is java.io.InputStream.
- *
- * @deprecated The charset unicode is platform specific and InputStream
- * deals with bytes not chars. Use getRederForText().
- */
-public static final DataFlavor plainTextFlavor;
-
-/**
- * This is the data flavor used for transferring Java strings. The
- * MIME type is "application/x-java-serialized-object" and the
- * representation class is java.lang.String.
- */
-public static final DataFlavor stringFlavor;
-
-/**
- * This is a data flavor used for transferring lists of files. The
- * representation type is a java.util.List, with each element of
- * the list being a java.io.File.
- */
-public static final DataFlavor javaFileListFlavor;
-
-/**
- * This is an image flavor used for transferring images. The
- * representation type is a java.awt.Image.
- */
-public static final DataFlavor imageFlavor;
-
-/**
- * This is the MIME type used for transferring a serialized object.
- * The representation class is the type of object be deserialized.
- */
-public static final String javaSerializedObjectMimeType =
- "application/x-java-serialized-object";
-
-/**
- * This is the MIME type used to transfer a Java object reference within
- * the same JVM. The representation class is the class of the object
- * being transferred.
- */
-public static final String javaJVMLocalObjectMimeType =
- "application/x-java-jvm-local-objectref";
-
-/**
- * This is the MIME type used to transfer a link to a remote object.
- * The representation class is the type of object being linked to.
- */
-public static final String javaRemoteObjectMimeType =
- "application/x-java-remote-object";
-
-static
-{
- plainTextFlavor
- = new DataFlavor(java.io.InputStream.class,
- "text/plain; charset=unicode",
- "plain unicode text");
-
- stringFlavor
- = new DataFlavor(java.lang.String.class,
- "Java Unicode String");
-
- javaFileListFlavor
- = new DataFlavor(java.util.List.class,
- "application/x-java-file-list; class=java.util.List",
- "Java File List");
-
- imageFlavor
- = new DataFlavor(java.awt.Image.class,
- "Java Image");
-}
-
-/*************************************************************************/
+ /**
+ * This is the data flavor used for tranferring plain text. The MIME
+ * type is "text/plain; charset=unicode". The representation class
+ * is java.io.InputStream.
+ *
+ * @deprecated The charset unicode is platform specific and InputStream
+ * deals with bytes not chars. Use getRederForText().
+ */
+ public static final DataFlavor plainTextFlavor =
+ new DataFlavor(java.io.InputStream.class,
+ "text/plain; charset=unicode",
+ "plain unicode text");
-/*
- * Instance Variables
- */
+ /**
+ * This is the data flavor used for transferring Java strings. The
+ * MIME type is "application/x-java-serialized-object" and the
+ * representation class is java.lang.String.
+ */
+ public static final DataFlavor stringFlavor =
+ new DataFlavor(java.lang.String.class, "Java Unicode String");
-// The MIME type for this flavor
-private final String mimeType;
+ /**
+ * This is a data flavor used for transferring lists of files. The
+ * representation type is a java.util.List, with each
+ * element of the list being a java.io.File.
+ */
+ public static final DataFlavor javaFileListFlavor =
+ new DataFlavor(java.util.List.class,
+ "application/x-java-file-list; class=java.util.List",
+ "Java File List");
-// The representation class for this flavor
-private final Class representationClass;
+ /**
+ * This is an image flavor used for transferring images. The
+ * representation type is a java.awt.Image.
+ */
+ public static final DataFlavor imageFlavor =
+ new DataFlavor(java.awt.Image.class, "Java Image");
-// The human readable name of this flavor
-private String humanPresentableName;
+ /**
+ * This is the MIME type used for transferring a serialized object.
+ * The representation class is the type of object be deserialized.
+ */
+ public static final String javaSerializedObjectMimeType =
+ "application/x-java-serialized-object";
-/*************************************************************************/
+ /**
+ * This is the MIME type used to transfer a Java object reference within
+ * the same JVM. The representation class is the class of the object
+ * being transferred.
+ */
+ public static final String javaJVMLocalObjectMimeType =
+ "application/x-java-jvm-local-objectref";
-/*
- * Static Methods
- */
+ /**
+ * This is the MIME type used to transfer a link to a remote object.
+ * The representation class is the type of object being linked to.
+ */
+ public static final String javaRemoteObjectMimeType =
+ "application/x-java-remote-object";
-/**
- * This method attempts to load the named class. The following class
- * loaders are searched in order: the bootstrap class loader, the
- * system class loader, the context class loader (if it exists), and
- * the specified fallback class loader.
- *
- * @param className The name of the class to load.
- * @param classLoader The class loader to use if all others fail, which
- * may be null.
- *
- * @exception ClassNotFoundException If the class cannot be loaded.
- */
-protected static final Class
-tryToLoadClass(String className, ClassLoader classLoader)
- throws ClassNotFoundException
-{
- try
- {
- return(Class.forName(className));
- }
- catch(Exception e) { ; }
- // Commented out for Java 1.1
/*
- try
- {
- return(className.getClass().getClassLoader().findClass(className));
- }
- catch(Exception e) { ; }
-
- try
- {
- return(ClassLoader.getSystemClassLoader().findClass(className));
- }
- catch(Exception e) { ; }
- */
+ * Instance Variables
+ */
+
+ // The MIME type for this flavor
+ private final String mimeType;
+
+ // The representation class for this flavor
+ private final Class representationClass;
+
+ // The human readable name of this flavor
+ private String humanPresentableName;
- // FIXME: What is the context class loader?
/*
- try
+ * Static Methods
+ */
+
+ /**
+ * This method attempts to load the named class. The following class
+ * loaders are searched in order: the bootstrap class loader, the
+ * system class loader, the context class loader (if it exists), and
+ * the specified fallback class loader.
+ *
+ * @param className The name of the class to load.
+ * @param classLoader The class loader to use if all others fail, which
+ * may be null.
+ *
+ * @exception ClassNotFoundException If the class cannot be loaded.
+ */
+ protected static final Class tryToLoadClass(String className,
+ ClassLoader classLoader)
+ throws ClassNotFoundException
+ {
+ try
+ {
+ return(Class.forName(className));
+ }
+ catch(Exception e) { ; }
+ // Commented out for Java 1.1
+ /*
+ try
+ {
+ return(className.getClass().getClassLoader().findClass(className));
+ }
+ catch(Exception e) { ; }
+
+ try
+ {
+ return(ClassLoader.getSystemClassLoader().findClass(className));
+ }
+ catch(Exception e) { ; }
+ */
+
+ // FIXME: What is the context class loader?
+ /*
+ try
+ {
+ }
+ catch(Exception e) { ; }
+ */
+
+ if (classLoader != null)
+ return(classLoader.loadClass(className));
+ else
+ throw new ClassNotFoundException(className);
+ }
+
+ private static Class getRepresentationClassFromMime(String mimeString,
+ ClassLoader classLoader)
{
+ String classname = getParameter("class", mimeString);
+ if (classname != null)
+ {
+ try
+ {
+ return tryToLoadClass(classname, classLoader);
+ }
+ catch(Exception e)
+ {
+ throw new IllegalArgumentException("classname: " + e.getMessage());
+ }
+ }
+ else
+ return java.io.InputStream.class;
}
- catch(Exception e) { ; }
- */
-
- if (classLoader != null)
- return(classLoader.loadClass(className));
- else
- throw new ClassNotFoundException(className);
-}
-
-/*************************************************************************/
+
+ /**
+ * Returns the value of the named MIME type parameter, or null
+ * if the parameter does not exist. Given the parameter name and the mime
+ * string.
+ *
+ * @param paramName The name of the parameter.
+ * @param mimeString The mime string from where the name should be found.
+ *
+ * @return The value of the parameter or null.
+ */
+ private static String getParameter(String paramName, String mimeString)
+ {
+ int idx = mimeString.indexOf(paramName + "=");
+ if (idx == -1)
+ return(null);
+
+ String value = mimeString.substring(idx + paramName.length() + 1);
+
+ idx = value.indexOf(" ");
+ if (idx == -1)
+ return(value);
+ else
+ return(value.substring(0, idx));
+ }
+
+ /**
+ * XXX - Currently returns plainTextFlavor.
+ */
+ public static final DataFlavor getTextPlainUnicodeFlavor()
+ {
+ return plainTextFlavor;
+ }
+
+ /**
+ * Selects the best supported text flavor on this implementation.
+ * Returns null when none of the given flavors is liked.
+ *
+ * The DataFlavor returned the first data flavor in the
+ * array that has either a representation class which is (a subclass of)
+ * Reader or String, or has a representation
+ * class which is (a subclass of) InputStream and has a
+ * primary MIME type of "text" and has an supported encoding.
+ */
+ public static final DataFlavor
+ selectBestTextFlavor(DataFlavor[] availableFlavors)
+ {
+ for(int i = 0; i < availableFlavors.length; i++)
+ {
+ DataFlavor df = availableFlavors[i];
+ Class c = df.representationClass;
+
+ // A Reader or String is good.
+ if ((Reader.class.isAssignableFrom(c))
+ || (String.class.isAssignableFrom(c)))
+ return df;
+
+ // A InputStream is good if the mime primary type is "text"
+ if ((InputStream.class.isAssignableFrom(c))
+ && ("text".equals(df.getPrimaryType())))
+ {
+ String encoding = availableFlavors[i].getParameter("charset");
+ if (encoding == null)
+ encoding = "us-ascii";
+ Reader r = null;
+ try
+ {
+ // Try to construct a dummy reader with the found encoding
+ r = new InputStreamReader
+ (new ByteArrayInputStream(new byte[0]), encoding);
+ }
+ catch(UnsupportedEncodingException uee) { /* ignore */ }
+
+ if (r != null)
+ return df;
+ }
+ }
+
+ // Nothing found
+ return null;
+ }
-/*
- * Constructors
- */
-/**
- * Empty public constructor needed for externalization.
- * Should not be used for normal instantiation.
- */
-public
-DataFlavor()
-{
+ /*
+ * Constructors
+ */
+
+ /**
+ * Empty public constructor needed for externalization.
+ * Should not be used for normal instantiation.
+ */
+ public DataFlavor()
+ {
mimeType = null;
representationClass = null;
humanPresentableName = null;
-}
-
-/*************************************************************************/
+ }
-/**
- * Private constructor.
- */
-private
-DataFlavor(Class representationClass,
- String mimeType,
- String humanPresentableName)
-{
+ /**
+ * Private constructor.
+ */
+ private DataFlavor(Class representationClass,
+ String mimeType,
+ String humanPresentableName)
+ {
this.representationClass = representationClass;
this.mimeType = mimeType;
if (humanPresentableName != null)
- this.humanPresentableName = humanPresentableName;
+ this.humanPresentableName = humanPresentableName;
else
- this.humanPresentableName = mimeType;
-}
-
-/*************************************************************************/
+ this.humanPresentableName = mimeType;
+ }
-/**
- * Initializes a new instance of DataFlavor. The class
- * and human readable name are specified, the MIME type will be
- * "application/x-java-serialized-object". If the human readable name
- * is not specified (null) then the human readable name
- * will be the same as the MIME type.
- *
- * @param representationClass The representation class for this object.
- * @param humanPresentableName The display name of the object.
- */
-public
-DataFlavor(Class representationClass, String humanPresentableName)
-{
+ /**
+ * Initializes a new instance of DataFlavor. The class
+ * and human readable name are specified, the MIME type will be
+ * "application/x-java-serialized-object". If the human readable name
+ * is not specified (null) then the human readable name
+ * will be the same as the MIME type.
+ *
+ * @param representationClass The representation class for this object.
+ * @param humanPresentableName The display name of the object.
+ */
+ public DataFlavor(Class representationClass, String humanPresentableName)
+ {
this(representationClass,
- "application/x-java-serialized-object"
- + "; class="
- + representationClass.getName(),
- humanPresentableName);
-}
-
-/*************************************************************************/
-
-/**
- * Initializes a new instance of DataFlavor with the
- * specified MIME type and description. If the MIME type has a
- * "class=<rep class>" parameter then the representation class will
- * be the class name specified. Otherwise the class defaults to
- * java.io.InputStream. If the human readable name
- * is not specified (null) then the human readable name
- * will be the same as the MIME type.
- *
- * @param mimeType The MIME type for this flavor.
- * @param humanPresentableName The display name of this flavor.
- * @param classLoader The class loader for finding classes if the default
- * class loaders do not work.
- *
- * @exception IllegalArgumentException If the representation class
- * specified cannot be loaded.
- * @exception ClassNotFoundException If the class is not loaded.
- */
-public
-DataFlavor(String mimeType, String humanPresentableName,
- ClassLoader classLoader) throws ClassNotFoundException
-{
- this(getRepresentationClassFromMime(mimeType, classLoader),
- mimeType, humanPresentableName);
-}
-
-private static Class
-getRepresentationClassFromMime(String mimeString, ClassLoader classLoader)
-{
- String classname = getParameter("class", mimeString);
- if (classname != null)
- {
- try
- {
- return tryToLoadClass(classname, classLoader);
- }
- catch(Exception e)
- {
- throw new IllegalArgumentException("classname: " + e.getMessage());
- }
- }
- else
- {
- return java.io.InputStream.class;
- }
-}
-
-/*************************************************************************/
-
-/**
- * Initializes a new instance of DataFlavor with the
- * specified MIME type and description. If the MIME type has a
- * "class=<rep class>" parameter then the representation class will
- * be the class name specified. Otherwise the class defaults to
- * java.io.InputStream. If the human readable name
- * is not specified (null) then the human readable name
- * will be the same as the MIME type. This is the same as calling
- * new DataFlavor(mimeType, humanPresentableName, null).
- *
- * @param mimeType The MIME type for this flavor.
- * @param humanPresentableName The display name of this flavor.
- *
- * @exception IllegalArgumentException If the representation class
- * specified cannot be loaded.
- */
-public
-DataFlavor(String mimeType, String humanPresentableName)
-{
- this (getRepresentationClassFromMime (mimeType, null),
- mimeType, humanPresentableName);
-}
-
-/*************************************************************************/
-
-/**
- * Initializes a new instance of DataFlavor with the specified
- * MIME type. This type can have a "class=" parameter to specify the
- * representation class, and then the class must exist or an exception will
- * be thrown. If there is no "class=" parameter then the representation class
- * will be java.io.InputStream. This is the same as calling
- * new DataFlavor(mimeType, null).
- *
- * @param mimeType The MIME type for this flavor.
- *
- * @exception IllegalArgumentException If a class is not specified in
- * the MIME type.
- * @exception ClassNotFoundException If the class cannot be loaded.
- */
-public
-DataFlavor(String mimeType) throws ClassNotFoundException
-{
- this(mimeType, null);
-}
-
-/*************************************************************************/
-
-/**
- * Returns the MIME type of this flavor.
- *
- * @return The MIME type for this flavor.
- */
-public String
-getMimeType()
-{
- return(mimeType);
-}
-
-/*************************************************************************/
-
-/**
- * Returns the representation class for this flavor.
- *
- * @return The representation class for this flavor.
- */
-public Class
-getRepresentationClass()
-{
- return(representationClass);
-}
-
-/*************************************************************************/
-
-/**
- * Returns the human presentable name for this flavor.
- *
- * @return The human presentable name for this flavor.
- */
-public String
-getHumanPresentableName()
-{
- return(humanPresentableName);
-}
-
-/*************************************************************************/
-
-/**
- * Returns the primary MIME type for this flavor.
- *
- * @return The primary MIME type for this flavor.
- */
-public String
-getPrimaryType()
-{
- int idx = mimeType.indexOf("/");
- if (idx == -1)
- return(mimeType);
-
- return(mimeType.substring(0, idx));
-}
-
-/*************************************************************************/
-
-/**
- * Returns the MIME subtype for this flavor.
- *
- * @return The MIME subtype for this flavor.
- */
-public String
-getSubType()
-{
- int start = mimeType.indexOf("/");
- if (start == -1)
- return "";
-
- int end = mimeType.indexOf(";", start + 1);
- if (end == -1)
- return mimeType.substring(start + 1);
- else
- return mimeType.substring(start + 1, end);
-}
-
-/*************************************************************************/
-
-/**
- * Returns the value of the named MIME type parameter, or null
- * if the parameter does not exist. Given the parameter name and the mime
- * string.
- *
- * @param paramName The name of the parameter.
- * @param mimeString The mime string from where the name should be found.
- *
- * @return The value of the parameter or null.
- */
-private static String
-getParameter(String paramName, String mimeString)
-{
- int idx = mimeString.indexOf(paramName + "=");
- if (idx == -1)
- return(null);
-
- String value = mimeString.substring(idx + paramName.length() + 1);
-
- idx = value.indexOf(" ");
- if (idx == -1)
- return(value);
- else
- return(value.substring(0, idx));
-}
-
-/*************************************************************************/
-
-/**
- * Returns the value of the named MIME type parameter, or null
- * if the parameter does not exist.
- *
- * @param paramName The name of the paramter.
- *
- * @return The value of the parameter.
- */
-public String
-getParameter(String paramName)
-{
- if ("humanPresentableName".equals(paramName))
- return getHumanPresentableName();
-
- return getParameter(paramName, mimeType);
-}
-
-/*************************************************************************/
-
-/**
- * Sets the human presentable name to the specified value.
- *
- * @param humanPresentableName The new display name.
- */
-public void
-setHumanPresentableName(String humanPresentableName)
-{
- this.humanPresentableName = humanPresentableName;
-}
-
-/*************************************************************************/
-
-/**
- * Tests the MIME type of this object for equality against the specified
- * MIME type. Ignores parameters.
- *
- * @param mimeType The MIME type to test against.
- *
- * @return true if the MIME type is equal to this object's
- * MIME type (ignoring parameters), false otherwise.
- *
- * @exception NullPointerException If mimeType is null.
- */
-public boolean
-isMimeTypeEqual(String mimeType)
-{
- String mime = getMimeType();
- int i = mime.indexOf(";");
- if (i != -1)
- mime = mime.substring(0, i);
-
- i = mimeType.indexOf(";");
- if (i != -1)
- mimeType = mimeType.substring(0, i);
-
- return mime.equals(mimeType);
-}
-
-/*************************************************************************/
-
-/**
- * Tests the MIME type of this object for equality against the specified
- * data flavor's MIME type
- *
- * @param flavor The flavor to test against.
- *
- * @return true if the flavor's MIME type is equal to this
- * object's MIME type, false otherwise.
- */
-public final boolean
-isMimeTypeEqual(DataFlavor flavor)
-{
- return(isMimeTypeEqual(flavor.getMimeType()));
-}
-
-/*************************************************************************/
-
-/**
- * Tests whether or not this flavor represents a serialized object.
- *
- * @return true if this flavor represents a serialized
- * object, false otherwise.
- */
-public boolean
-isMimeTypeSerializedObject()
-{
- return(mimeType.startsWith(javaSerializedObjectMimeType));
-}
-
-/*************************************************************************/
-
-/**
- * Tests whether or not this flavor has a representation class of
- * java.io.InputStream.
- *
- * @return true if the representation class of this flavor
- * is java.io.InputStream, false otherwise.
- */
-public boolean
-isRepresentationClassInputStream()
-{
- return(representationClass.getName().equals("java.io.InputStream"));
-}
-
-/*************************************************************************/
-
-/**
- * Tests whether the representation class for this flavor is
- * serializable.
- *
- * @return true if the representation class is serializable,
- * false otherwise.
- */
-public boolean
-isRepresentationClassSerializable()
-{
- Class[] interfaces = representationClass.getInterfaces();
-
- int i = 0;
- while (i < interfaces.length)
- {
- if (interfaces[i].getName().equals("java.io.Serializable"))
- return(true);
- ++i;
- }
-
- return(false);
-}
-
-/*************************************************************************/
-
-/**
- * Tests whether the representation class for his flavor is remote.
- *
- * @return true if the representation class is remote,
- * false otherwise.
- */
-public boolean
-isRepresentationClassRemote()
-{
- return Remote.class.isAssignableFrom (representationClass);
-}
-
-/*************************************************************************/
-
-/**
- * Tests whether or not this flavor represents a serialized object.
- *
- * @return true if this flavor represents a serialized
- * object, false otherwise.
- */
-public boolean
-isFlavorSerializedObjectType()
-{
- // FIXME: What is the diff between this and isMimeTypeSerializedObject?
- return(mimeType.startsWith(javaSerializedObjectMimeType));
-}
-
-/*************************************************************************/
-
-/**
- * Tests whether or not this flavor represents a remote object.
- *
- * @return true if this flavor represents a remote object,
- * false otherwise.
- */
-public boolean
-isFlavorRemoteObjectType()
-{
- return(mimeType.startsWith(javaRemoteObjectMimeType));
-}
-
-/*************************************************************************/
-
-/**
- * Tests whether or not this flavor represents a list of files.
- *
- * @return true if this flavor represents a list of files,
- * false otherwise.
- */
-public boolean
-isFlavorJavaFileListType()
-{
- if (this.mimeType.equals(javaFileListFlavor.mimeType) &&
- this.representationClass.equals(javaFileListFlavor.representationClass))
- return(true);
-
- return(false);
-}
-
-/*************************************************************************/
+ "application/x-java-serialized-object"
+ + "; class="
+ + representationClass.getName(),
+ humanPresentableName);
+ }
-/**
- * Returns a copy of this object.
- *
- * @return A copy of this object.
- *
- * @exception CloneNotSupportedException If the object's class does not support
- * the Cloneable interface. Subclasses that override the clone method can also
- * throw this exception to indicate that an instance cannot be cloned.
- */
-public Object clone () throws CloneNotSupportedException
-{
- try
- {
- return(super.clone());
- }
- catch(Exception e)
- {
- return(null);
- }
-}
+ /**
+ * Initializes a new instance of DataFlavor with the
+ * specified MIME type and description. If the MIME type has a
+ * "class=<rep class>" parameter then the representation class will
+ * be the class name specified. Otherwise the class defaults to
+ * java.io.InputStream. If the human readable name
+ * is not specified (null) then the human readable name
+ * will be the same as the MIME type.
+ *
+ * @param mimeType The MIME type for this flavor.
+ * @param humanPresentableName The display name of this flavor.
+ * @param classLoader The class loader for finding classes if the default
+ * class loaders do not work.
+ *
+ * @exception IllegalArgumentException If the representation class
+ * specified cannot be loaded.
+ * @exception ClassNotFoundException If the class is not loaded.
+ */
+ public DataFlavor(String mimeType, String humanPresentableName,
+ ClassLoader classLoader)
+ throws ClassNotFoundException
+ {
+ this(getRepresentationClassFromMime(mimeType, classLoader),
+ mimeType, humanPresentableName);
+ }
-/*************************************************************************/
+ /**
+ * Initializes a new instance of DataFlavor with the
+ * specified MIME type and description. If the MIME type has a
+ * "class=<rep class>" parameter then the representation class will
+ * be the class name specified. Otherwise the class defaults to
+ * java.io.InputStream. If the human readable name
+ * is not specified (null) then the human readable name
+ * will be the same as the MIME type. This is the same as calling
+ * new DataFlavor(mimeType, humanPresentableName, null).
+ *
+ * @param mimeType The MIME type for this flavor.
+ * @param humanPresentableName The display name of this flavor.
+ *
+ * @exception IllegalArgumentException If the representation class
+ * specified cannot be loaded.
+ */
+ public DataFlavor(String mimeType, String humanPresentableName)
+ {
+ this(getRepresentationClassFromMime (mimeType, null),
+ mimeType, humanPresentableName);
+ }
-/**
- * This method test the specified DataFlavor for equality
- * against this object. This will be true if the MIME type and
- * representation type are the equal.
- *
- * @param flavor The DataFlavor to test against.
- *
- * @return true if the flavor is equal to this object,
- * false otherwise.
- */
-public boolean
-equals(DataFlavor flavor)
-{
- if (flavor == null)
- return(false);
+ /**
+ * Initializes a new instance of DataFlavor with the specified
+ * MIME type. This type can have a "class=" parameter to specify the
+ * representation class, and then the class must exist or an exception will
+ * be thrown. If there is no "class=" parameter then the representation class
+ * will be java.io.InputStream. This is the same as calling
+ * new DataFlavor(mimeType, null).
+ *
+ * @param mimeType The MIME type for this flavor.
+ *
+ * @exception IllegalArgumentException If a class is not specified in
+ * the MIME type.
+ * @exception ClassNotFoundException If the class cannot be loaded.
+ */
+ public DataFlavor(String mimeType) throws ClassNotFoundException
+ {
+ this(mimeType, null);
+ }
- if (!this.mimeType.toLowerCase().equals(flavor.mimeType.toLowerCase()))
- return(false);
+ /**
+ * Returns the MIME type of this flavor.
+ *
+ * @return The MIME type for this flavor.
+ */
+ public String getMimeType()
+ {
+ return(mimeType);
+ }
- if (!this.representationClass.equals(flavor.representationClass))
- return(false);
+ /**
+ * Returns the representation class for this flavor.
+ *
+ * @return The representation class for this flavor.
+ */
+ public Class getRepresentationClass()
+ {
+ return(representationClass);
+ }
- return(true);
-}
+ /**
+ * Returns the human presentable name for this flavor.
+ *
+ * @return The human presentable name for this flavor.
+ */
+ public String getHumanPresentableName()
+ {
+ return(humanPresentableName);
+ }
-/*************************************************************************/
+ /**
+ * Returns the primary MIME type for this flavor.
+ *
+ * @return The primary MIME type for this flavor.
+ */
+ public String getPrimaryType()
+ {
+ int idx = mimeType.indexOf("/");
+ if (idx == -1)
+ return(mimeType);
+
+ return(mimeType.substring(0, idx));
+ }
-/**
- * This method test the specified Object for equality
- * against this object. This will be true if the following conditions
- * are met:
- *
- *
- *
- * @param obj The null.DataFlavor.Object to test against.
- *
- * @return true if the flavor is equal to this object,
- * false otherwise.
- */
-public boolean
-equals(Object obj)
-{
- if (!(obj instanceof DataFlavor))
- return(false);
+ /**
+ * Returns the MIME subtype for this flavor.
+ *
+ * @return The MIME subtype for this flavor.
+ */
+ public String getSubType()
+ {
+ int start = mimeType.indexOf("/");
+ if (start == -1)
+ return "";
+
+ int end = mimeType.indexOf(";", start + 1);
+ if (end == -1)
+ return mimeType.substring(start + 1);
+ else
+ return mimeType.substring(start + 1, end);
+ }
- return(equals((DataFlavor)obj));
-}
+ /**
+ * Returns the value of the named MIME type parameter, or null
+ * if the parameter does not exist.
+ *
+ * @param paramName The name of the paramter.
+ *
+ * @return The value of the parameter.
+ */
+ public String getParameter(String paramName)
+ {
+ if ("humanPresentableName".equals(paramName))
+ return getHumanPresentableName();
+
+ return getParameter(paramName, mimeType);
+ }
-/*************************************************************************/
+ /**
+ * Sets the human presentable name to the specified value.
+ *
+ * @param humanPresentableName The new display name.
+ */
+ public void setHumanPresentableName(String humanPresentableName)
+ {
+ this.humanPresentableName = humanPresentableName;
+ }
-/**
- * Tests whether or not the specified string is equal to the MIME type
- * of this object.
- *
- * @param str The string to test against.
- *
- * @return true if the string is equal to this object's MIME
- * type, false otherwise.
- *
- * @deprecated Not compatible with hashCode().
- * Use isMimeTypeEqual()
- */
-public boolean
-equals(String str)
-{
- return(isMimeTypeEqual(str));
-}
+ /**
+ * Tests the MIME type of this object for equality against the specified
+ * MIME type. Ignores parameters.
+ *
+ * @param mimeType The MIME type to test against.
+ *
+ * @return true if the MIME type is equal to this object's
+ * MIME type (ignoring parameters), false otherwise.
+ *
+ * @exception NullPointerException If mimeType is null.
+ */
+ public boolean isMimeTypeEqual(String mimeType)
+ {
+ String mime = getMimeType();
+ int i = mime.indexOf(";");
+ if (i != -1)
+ mime = mime.substring(0, i);
+
+ i = mimeType.indexOf(";");
+ if (i != -1)
+ mimeType = mimeType.substring(0, i);
+
+ return mime.equals(mimeType);
+ }
-/*************************************************************************/
+ /**
+ * Tests the MIME type of this object for equality against the specified
+ * data flavor's MIME type
+ *
+ * @param flavor The flavor to test against.
+ *
+ * @return true if the flavor's MIME type is equal to this
+ * object's MIME type, false otherwise.
+ */
+ public final boolean isMimeTypeEqual(DataFlavor flavor)
+ {
+ return isMimeTypeEqual(flavor.getMimeType());
+ }
-/**
- * Returns the hash code for this data flavor.
- * The hash code is based on the (lower case) mime type and the
- * representation class.
- */
-public int
-hashCode()
-{
- return(mimeType.toLowerCase().hashCode()^representationClass.hashCode());
-}
+ /**
+ * Tests whether or not this flavor represents a serialized object.
+ *
+ * @return true if this flavor represents a serialized
+ * object, false otherwise.
+ */
+ public boolean isMimeTypeSerializedObject()
+ {
+ return mimeType.startsWith(javaSerializedObjectMimeType);
+ }
-/*************************************************************************/
+ /**
+ * Tests whether or not this flavor has a representation class of
+ * java.io.InputStream.
+ *
+ * @return true if the representation class of this flavor
+ * is java.io.InputStream, false otherwise.
+ */
+ public boolean isRepresentationClassInputStream()
+ {
+ return representationClass.getName().equals("java.io.InputStream");
+ }
-/**
- * Returns true when the given DataFlavor
- * matches this one.
- */
-public boolean
-match(DataFlavor dataFlavor)
-{
- // XXX - How is this different from equals?
- return(equals(dataFlavor));
-}
+ /**
+ * Tests whether the representation class for this flavor is
+ * serializable.
+ *
+ * @return true if the representation class is serializable,
+ * false otherwise.
+ */
+ public boolean isRepresentationClassSerializable()
+ {
+ Class[] interfaces = representationClass.getInterfaces();
+
+ int i = 0;
+ while (i < interfaces.length)
+ {
+ if (interfaces[i].getName().equals("java.io.Serializable"))
+ return true;
+ ++i;
+ }
+
+ return false;
+ }
-/*************************************************************************/
+ /**
+ * Tests whether the representation class for his flavor is remote.
+ *
+ * @return true if the representation class is remote,
+ * false otherwise.
+ */
+ public boolean isRepresentationClassRemote()
+ {
+ return Remote.class.isAssignableFrom (representationClass);
+ }
-/**
- * This method exists for backward compatibility. It simply returns
- * the same name/value pair passed in.
- *
- * @param name The parameter name.
- * @param value The parameter value.
- *
- * @return The name/value pair.
- *
- * @deprecated
- */
-protected String
-normalizeMimeTypeParameter(String name, String value)
-{
- return(name + "=" + value);
-}
+ /**
+ * Tests whether or not this flavor represents a serialized object.
+ *
+ * @return true if this flavor represents a serialized
+ * object, false otherwise.
+ */
+ public boolean isFlavorSerializedObjectType()
+ {
+ // FIXME: What is the diff between this and isMimeTypeSerializedObject?
+ return(mimeType.startsWith(javaSerializedObjectMimeType));
+ }
-/*************************************************************************/
+ /**
+ * Tests whether or not this flavor represents a remote object.
+ *
+ * @return true if this flavor represents a remote object,
+ * false otherwise.
+ */
+ public boolean isFlavorRemoteObjectType()
+ {
+ return(mimeType.startsWith(javaRemoteObjectMimeType));
+ }
-/**
- * This method exists for backward compatibility. It simply returns
- * the MIME type string unchanged.
- *
- * @param type The MIME type.
- *
- * @return The MIME type.
- *
- * @deprecated
- */
-protected String
-normalizeMimeType(String type)
-{
- return(type);
-}
+ /**
+ * Tests whether or not this flavor represents a list of files.
+ *
+ * @return true if this flavor represents a list of files,
+ * false otherwise.
+ */
+ public boolean isFlavorJavaFileListType()
+ {
+ if (mimeType.equals(javaFileListFlavor.mimeType)
+ && representationClass.equals(javaFileListFlavor.representationClass))
+ return true;
+
+ return false ;
+ }
-/*************************************************************************/
+ /**
+ * Returns a copy of this object.
+ *
+ * @return A copy of this object.
+ *
+ * @exception CloneNotSupportedException If the object's class does not support
+ * the Cloneable interface. Subclasses that override the clone method can also
+ * throw this exception to indicate that an instance cannot be cloned.
+ */
+ public Object clone () throws CloneNotSupportedException
+ {
+ // FIXME - This cannot be right.
+ try
+ {
+ return super.clone();
+ }
+ catch(Exception e)
+ {
+ return null;
+ }
+ }
-/**
- * Serialize this class.
- *
- * @param stream The ObjectOutput stream to serialize to.
- *
- * @exception IOException If an error occurs.
- */
-public void
-writeExternal(ObjectOutput stream) throws IOException
-{
- // FIXME: Implement me
-}
+ /**
+ * This method test the specified DataFlavor for equality
+ * against this object. This will be true if the MIME type and
+ * representation type are the equal.
+ *
+ * @param flavor The DataFlavor to test against.
+ *
+ * @return true if the flavor is equal to this object,
+ * false otherwise.
+ */
+ public boolean equals(DataFlavor flavor)
+ {
+ if (flavor == null)
+ return false;
+
+ if (! this.mimeType.toLowerCase().equals(flavor.mimeType.toLowerCase()))
+ return false;
+
+ if (! this.representationClass.equals(flavor.representationClass))
+ return false;
+
+ return true;
+ }
-/*************************************************************************/
+ /**
+ * This method test the specified Object for equality
+ * against this object. This will be true if the following conditions
+ * are met:
+ *
+ *
+ *
+ * @param obj The null.DataFlavor.Object to test against.
+ *
+ * @return true if the flavor is equal to this object,
+ * false otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if (! (obj instanceof DataFlavor))
+ return false;
+
+ return equals((DataFlavor) obj);
+ }
-/**
- * De-serialize this class.
- *
- * @param stream The ObjectInput stream to deserialize from.
- *
- * @exception IOException If an error ocurs.
- * @exception ClassNotFoundException If the class for an object being restored
- * cannot be found.
- */
-public void
-readExternal(ObjectInput stream) throws IOException, ClassNotFoundException
-{
- // FIXME: Implement me
-}
+ /**
+ * Tests whether or not the specified string is equal to the MIME type
+ * of this object.
+ *
+ * @param str The string to test against.
+ *
+ * @return true if the string is equal to this object's MIME
+ * type, false otherwise.
+ *
+ * @deprecated Not compatible with hashCode().
+ * Use isMimeTypeEqual()
+ */
+ public boolean equals(String str)
+ {
+ return isMimeTypeEqual(str);
+ }
-/*************************************************************************/
+ /**
+ * Returns the hash code for this data flavor.
+ * The hash code is based on the (lower case) mime type and the
+ * representation class.
+ */
+ public int hashCode()
+ {
+ return mimeType.toLowerCase().hashCode() ^ representationClass.hashCode();
+ }
-/**
- * Returns a string representation of this DataFlavor. Including the
- * representation class name, MIME type and human presentable name.
- */
-public String
-toString()
-{
- return(getClass().getName()
- + "[representationClass=" + getRepresentationClass().getName()
- + ",mimeType=" + getMimeType()
- + ",humanPresentableName=" + getHumanPresentableName()
- + "]");
-}
+ /**
+ * Returns true when the given DataFlavor
+ * matches this one.
+ */
+ public boolean match(DataFlavor dataFlavor)
+ {
+ // XXX - How is this different from equals?
+ return equals(dataFlavor);
+ }
-/*************************************************************************/
+ /**
+ * This method exists for backward compatibility. It simply returns
+ * the same name/value pair passed in.
+ *
+ * @param name The parameter name.
+ * @param value The parameter value.
+ *
+ * @return The name/value pair.
+ *
+ * @deprecated
+ */
+ protected String normalizeMimeTypeParameter(String name, String value)
+ {
+ return name + "=" + value;
+ }
-/**
- * XXX - Currently returns plainTextFlavor.
- */
-public static final DataFlavor
-getTextPlainUnicodeFlavor()
-{
- return(plainTextFlavor);
-}
+ /**
+ * This method exists for backward compatibility. It simply returns
+ * the MIME type string unchanged.
+ *
+ * @param type The MIME type.
+ *
+ * @return The MIME type.
+ *
+ * @deprecated
+ */
+ protected String normalizeMimeType(String type)
+ {
+ return type;
+ }
-/*************************************************************************/
+ /**
+ * Serialize this class.
+ *
+ * @param stream The ObjectOutput stream to serialize to.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void writeExternal(ObjectOutput stream) throws IOException
+ {
+ // FIXME: Implement me
+ }
-/**
- * XXX - Currently returns java.io.InputStream.
- *
- * @since 1.3
- */
-public final Class
-getDefaultRepresentationClass()
-{
- return(java.io.InputStream.class);
-}
-/*************************************************************************/
-/**
- * XXX - Currently returns java.io.InputStream.
- */
-public final String
-getDefaultRepresentationClassAsString()
-{
- return(getDefaultRepresentationClass().getName());
-}
+ /**
+ * De-serialize this class.
+ *
+ * @param stream The ObjectInput stream to deserialize from.
+ *
+ * @exception IOException If an error ocurs.
+ * @exception ClassNotFoundException If the class for an object being restored
+ * cannot be found.
+ */
+ public void readExternal(ObjectInput stream)
+ throws IOException, ClassNotFoundException
+ {
+ // FIXME: Implement me
+ }
-/*************************************************************************/
+ /**
+ * Returns a string representation of this DataFlavor. Including the
+ * representation class name, MIME type and human presentable name.
+ */
+ public String toString()
+ {
+ return (getClass().getName()
+ + "[representationClass=" + getRepresentationClass().getName()
+ + ",mimeType=" + getMimeType()
+ + ",humanPresentableName=" + getHumanPresentableName()
+ + "]");
+ }
-/**
- * Selects the best supported text flavor on this implementation.
- * Returns null when none of the given flavors is liked.
- *
- * The DataFlavor returned the first data flavor in the
- * array that has either a representation class which is (a subclass of)
- * Reader or String, or has a representation
- * class which is (a subclass of) InputStream and has a
- * primary MIME type of "text" and has an supported encoding.
- */
-public static final DataFlavor
-selectBestTextFlavor(DataFlavor[] availableFlavors)
-{
- for(int i=0; ijava.io.InputStream.
+ */
+ public final String getDefaultRepresentationClassAsString()
+ {
+ return getDefaultRepresentationClass().getName();
+ }
- // A InputStream is good if the mime primary type is "text"
- if ((InputStream.class.isAssignableFrom(c))
- && ("text".equals(df.getPrimaryType())))
+ /**
+ * Creates a Reader for a given Transferable.
+ *
+ * If the representation class is a (subclass of) Reader
+ * then an instance of the representation class is returned. If the
+ * representatation class is a String then a
+ * StringReader is returned. And if the representation class
+ * is a (subclass of) InputStream and the primary MIME type
+ * is "text" then a InputStreamReader for the correct charset
+ * encoding is returned.
+ *
+ * @param transferable The Transferable for which a text
+ * Reader is requested.
+ *
+ * @exception IllegalArgumentException If the representation class is not one
+ * of the seven listed above or the Transferable has null data.
+ * @exception NullPointerException If the Transferable is null.
+ * @exception UnsupportedFlavorException when the transferable doesn't
+ * support this DataFlavor. Or if the representable class
+ * isn't a (subclass of) Reader, String,
+ * InputStream and/or the primary MIME type isn't "text".
+ * @exception IOException when any IOException occurs.
+ * @exception UnsupportedEncodingException if the "charset" isn't supported
+ * on this platform.
+ */
+ public Reader getReaderForText(Transferable transferable)
+ throws UnsupportedFlavorException, IOException
+ {
+ if (!transferable.isDataFlavorSupported(this))
+ throw new UnsupportedFlavorException(this);
+
+ if (Reader.class.isAssignableFrom(representationClass))
+ return (Reader)transferable.getTransferData(this);
+
+ if (String.class.isAssignableFrom(representationClass))
+ return new StringReader((String)transferable.getTransferData(this));
+
+ if (InputStream.class.isAssignableFrom(representationClass)
+ && "text".equals(getPrimaryType()))
{
- String encoding = availableFlavors[i].getParameter("charset");
+ InputStream in = (InputStream)transferable.getTransferData(this);
+ String encoding = getParameter("charset");
if (encoding == null)
- encoding = "us-ascii";
- Reader r = null;
- try
- {
- // Try to construct a dummy reader with the found encoding
- r = new InputStreamReader
- (new ByteArrayInputStream(new byte[0]), encoding);
- }
- catch(UnsupportedEncodingException uee) { /* ignore */ }
- if (r != null)
- return df;
+ encoding = "us-ascii";
+ return new InputStreamReader(in, encoding);
}
- }
-
- // Nothing found
- return(null);
-}
-
-/*************************************************************************/
-
-/**
- * Creates a Reader for a given Transferable.
- *
- * If the representation class is a (subclass of) Reader
- * then an instance of the representation class is returned. If the
- * representatation class is a String then a
- * StringReader is returned. And if the representation class
- * is a (subclass of) InputStream and the primary MIME type
- * is "text" then a InputStreamReader for the correct charset
- * encoding is returned.
- *
- * @param transferable The Transferable for which a text
- * Reader is requested.
- *
- * @exception IllegalArgumentException If the representation class is not one
- * of the seven listed above or the Transferable has null data.
- * @exception NullPointerException If the Transferable is null.
- * @exception UnsupportedFlavorException when the transferable doesn't
- * support this DataFlavor. Or if the representable class
- * isn't a (subclass of) Reader, String,
- * InputStream and/or the primary MIME type isn't "text".
- * @exception IOException when any IOException occurs.
- * @exception UnsupportedEncodingException if the "charset" isn't supported
- * on this platform.
- */
-public Reader getReaderForText(Transferable transferable)
- throws UnsupportedFlavorException, IOException
-{
- if (!transferable.isDataFlavorSupported(this))
- throw new UnsupportedFlavorException(this);
-
- if (Reader.class.isAssignableFrom(representationClass))
- return((Reader)transferable.getTransferData(this));
-
- if (String.class.isAssignableFrom(representationClass))
- return(new StringReader((String)transferable.getTransferData(this)));
-
- if (InputStream.class.isAssignableFrom(representationClass)
- && "text".equals(getPrimaryType()))
- {
- InputStream in = (InputStream)transferable.getTransferData(this);
- String encoding = getParameter("charset");
- if (encoding == null)
- encoding = "us-ascii";
- return(new InputStreamReader(in, encoding));
- }
-
- throw new UnsupportedFlavorException(this);
-}
+
+ throw new UnsupportedFlavorException(this);
+ }
/**
* Returns whether the representation class for this DataFlavor is
@@ -1010,9 +883,9 @@ public Reader getReaderForText(Transferable transferable)
*
* @since 1.4
*/
- public boolean isRepresentationClassByteBuffer ()
+ public boolean isRepresentationClassByteBuffer()
{
- return ByteBuffer.class.isAssignableFrom (representationClass);
+ return ByteBuffer.class.isAssignableFrom(representationClass);
}
/**
@@ -1021,9 +894,9 @@ public Reader getReaderForText(Transferable transferable)
*
* @since 1.4
*/
- public boolean isRepresentationClassCharBuffer ()
+ public boolean isRepresentationClassCharBuffer()
{
- return CharBuffer.class.isAssignableFrom (representationClass);
+ return CharBuffer.class.isAssignableFrom(representationClass);
}
/**
@@ -1032,10 +905,67 @@ public Reader getReaderForText(Transferable transferable)
*
* @since 1.4
*/
- public boolean isRepresentationClassReader ()
+ public boolean isRepresentationClassReader()
{
- return Reader.class.isAssignableFrom (representationClass);
+ return Reader.class.isAssignableFrom(representationClass);
+ }
+
+ /**
+ * Returns whether this DataFlavor is a valid text flavor for
+ * this implementation of the Java platform. Only flavors equivalent to
+ * DataFlavor.stringFlavor and DataFlavors with
+ * a primary MIME type of "text" can be valid text flavors.
+ * DataFlavor.stringFlavor, or its representation must be
+ * java.io.Reader, java.lang.String,
+ * java.nio.CharBuffer, java.io.InputStream or
+ * java.nio.ByteBuffer,
+ * If the representation is java.io.InputStream or
+ * java.nio.ByteBuffer, then this flavor's charset
+ * parameter must be supported by this implementation of the Java platform.
+ * If a charset is not specified, then the platform default charset, which
+ * is always supported, is assumed.
+ * java.io.InputStream,
+ * java.nio.ByteBuffer.
+ * selectBestTextFlavor for a list of text flavors which
+ * support the charset parameter.
+ *
+ * @return true if this DataFlavor is a valid
+ * text flavor as described above; false otherwise
+ * @see #selectBestTextFlavor
+ * @since 1.4
+ */
+ public boolean isFlavorTextType() {
+ // FIXME: I'm not 100% sure if this implementation does the same like sun's does
+ if(equals(DataFlavor.stringFlavor) || getPrimaryType().equals("text"))
+ {
+ String charset = getParameter("charset");
+ Class c = getRepresentationClass();
+ if(charset != null)
+ {
+ if(Reader.class.isAssignableFrom(c)
+ || CharBuffer.class.isAssignableFrom(c)
+ || String.class.isAssignableFrom(c))
+ {
+ return true;
+ }
+ else if(InputStream.class.isAssignableFrom(c)
+ || ByteBuffer.class.isAssignableFrom(c))
+ {
+ return Charset.isSupported(charset);
+ }
+ }
+ else if(InputStream.class.isAssignableFrom(c)
+ || ByteBuffer.class.isAssignableFrom(c))
+ {
+ return true;
+ }
+ }
+ return false;
}
-
} // class DataFlavor
diff --git a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java
index f6530f5117c..7b4d2fbd38f 100644
--- a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java
+++ b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java
@@ -38,9 +38,11 @@ exception statement from your version. */
package java.awt.datatransfer;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.WeakHashMap;
/**
* This class maps between native platform type names and DataFlavors.
@@ -54,10 +56,28 @@ import java.util.Map;
public final class SystemFlavorMap implements FlavorMap, FlavorTable
{
/**
- * The default (instance) flavor map.
+ * The map which maps the thread's ClassLoaders to
+ * SystemFlavorMaps.
*/
- private static FlavorMap defaultFlavorMap;
-
+ private static final Map systemFlavorMaps = new WeakHashMap();
+
+ /**
+ * Constant which is used to prefix encode Java MIME types.
+ */
+ private static final String GNU_JAVA_MIME_PREFIX = "gnu.java:";
+
+ /**
+ * This map maps native Strings to lists of
+ * DataFlavors
+ */
+ private HashMap nativeToFlavorMap = new HashMap();
+
+ /**
+ * This map maps DataFlavors to lists of native
+ * Strings
+ */
+ private HashMap flavorToNativeMap = new HashMap();
+
/**
* Private constructor.
*/
@@ -98,47 +118,118 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
}
/**
- * Returns the default (instance) (System)FlavorMap.
+ * Returns the (System)FlavorMap for the current thread's
+ * ClassLoader.
*/
public static FlavorMap getDefaultFlavorMap ()
{
- if (defaultFlavorMap == null)
- defaultFlavorMap = new SystemFlavorMap ();
-
- return defaultFlavorMap;
+ ClassLoader classLoader = Thread.currentThread()
+ .getContextClassLoader();
+
+ //if ContextClassLoader not set, use system default
+ if (classLoader == null)
+ {
+ classLoader = ClassLoader.getSystemClassLoader();
+ }
+
+ synchronized(systemFlavorMaps)
+ {
+ FlavorMap map = (FlavorMap)
+ systemFlavorMaps.get(classLoader);
+ if (map == null)
+ {
+ map = new SystemFlavorMap();
+ systemFlavorMaps.put(classLoader, map);
+ }
+ return map;
+ }
}
/**
- * Returns the native type name for the given java mime type.
+ * Encodes a MIME type for use as a String native. The format
+ * of an encoded representation of a MIME type is implementation-dependent.
+ * The only restrictions are:
+ *
+ *
+ * null if and only if the
+ * MIME type String is null.null MIME type
+ * Strings are equal if and only if these Strings
+ * are equal according to String.equals(Object).String prefixed with gnu.java:.
+ *
+ * @param mime the MIME type to encode
+ * @return the encoded String, or null if
+ * mimeType is null
*/
public static String encodeJavaMIMEType (String mime)
{
- return null;
+ if (mime != null)
+ return GNU_JAVA_MIME_PREFIX + mime;
+ else
+ return null;
}
/**
- * Returns the native type name for the given data flavor.
+ * Encodes a DataFlavor for use as a String
+ * native. The format of an encoded DataFlavor is
+ * implementation-dependent. The only restrictions are:
+ *
+ *
+ * null if and only if the
+ * specified DataFlavor is null or its MIME type
+ * String is null.null
+ * DataFlavors with non-null MIME type
+ * Strings are equal if and only if the MIME type
+ * Strings of these DataFlavors are equal
+ * according to String.equals(Object).String of the specified DataFlavor prefixed
+ * with gnu.java:.
+ *
+ * @param df the DataFlavor to encode
+ * @return the encoded String, or null if
+ * flav is null or has a null MIME type
*/
public static String encodeDataFlavor (DataFlavor df)
{
- return null;
+ if (df != null)
+ {
+ return encodeJavaMIMEType(df.getMimeType());
+ }
+ else
+ return null;
}
/**
* Returns true if the native type name can be represented as
- * a java mime type.
+ * a java mime type. Returns false if parameter is
+ * null.
*/
public static boolean isJavaMIMEType (String name)
{
- return false;
+ return (name != null && name.startsWith(GNU_JAVA_MIME_PREFIX));
}
/**
- * Returns the java mime type for the given the native type name.
+ * Decodes a String native for use as a Java MIME type.
+ *
+ * @param name the String to decode
+ * @return the decoded Java MIME type, or null if nat
+ * is not an encoded String native
*/
public static String decodeJavaMIMEType (String name)
{
- return null;
+ if (isJavaMIMEType(name))
+ {
+ return name.substring(GNU_JAVA_MIME_PREFIX.length());
+ }
+ else
+ return null;
}
/**
@@ -156,6 +247,20 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable
return null;
}
+ /**
+ * Returns a List of DataFlavors to which the specified
+ * String native can be translated by the data transfer
+ * subsystem. The List will be sorted from best
+ * DataFlavor to worst. That is, the first DataFlavor
+ * will best reflect data in the specified native to a Java
+ * application.
+ * String native to a single
+ * DataFlavor. Unlike getFlavorsForNative, the
+ * mapping will only be established in one direction, and the native will
+ * not be encoded. To establish a two-way mapping, call
+ * addUnencodedNativeForFlavor as well. The new mapping will
+ * be of lower priority than any existing mapping.
+ * This method has no effect if a mapping from the specified
+ * String native to the specified or equal
+ * DataFlavor already exists.
+ *
+ * @param nativeStr the String native key for the mapping
+ * @param flavor the DataFlavor value for the mapping
+ * @throws NullPointerException if nat or flav is null
+ *
+ * @see #addUnencodedNativeForFlavor
+ * @since 1.4
+ */
+ public synchronized void addFlavorForUnencodedNative(String nativeStr,
+ DataFlavor flavor)
+ {
+ if ((nativeStr == null) || (flavor == null))
+ throw new NullPointerException();
+ List flavors = (List) nativeToFlavorMap.get(nativeStr);
+ if (flavors == null)
+ {
+ flavors = new ArrayList();
+ nativeToFlavorMap.put(nativeStr, flavors);
+ }
+ else
+ {
+ if (! flavors.contains(flavor))
+ flavors.add(flavor);
+ }
+ }
+
+ /**
+ * Adds a mapping from the specified DataFlavor (and all
+ * DataFlavors equal to the specified DataFlavor)
+ * to the specified String native.
+ * Unlike getNativesForFlavor, the mapping will only be
+ * established in one direction, and the native will not be encoded. To
+ * establish a two-way mapping, call
+ * addFlavorForUnencodedNative as well. The new mapping will
+ * be of lower priority than any existing mapping.
+ * This method has no effect if a mapping from the specified or equal
+ * DataFlavor to the specified String native
+ * already exists.
+ *
+ * @param flavor the DataFlavor key for the mapping
+ * @param nativeStr the String native value for the mapping
+ * @throws NullPointerException if flav or nat is null
+ *
+ * @see #addFlavorForUnencodedNative
+ * @since 1.4
+ */
+ public synchronized void addUnencodedNativeForFlavor(DataFlavor flavor,
+ String nativeStr)
+ {
+ if ((nativeStr == null) || (flavor == null))
+ throw new NullPointerException();
+ List natives = (List) flavorToNativeMap.get(flavor);
+ if (natives == null)
+ {
+ natives = new ArrayList();
+ flavorToNativeMap.put(flavor, natives);
+ }
+ else
+ {
+ if (! natives.contains(nativeStr))
+ natives.add(nativeStr);
+ }
+ }
+
+ /**
+ * Discards the current mappings for the specified DataFlavor
+ * and all DataFlavors equal to the specified
+ * DataFlavor, and creates new mappings to the
+ * specified String natives.
+ * Unlike getNativesForFlavor, the mappings will only be
+ * established in one direction, and the natives will not be encoded. To
+ * establish two-way mappings, call setFlavorsForNative
+ * as well. The first native in the array will represent the highest
+ * priority mapping. Subsequent natives will represent mappings of
+ * decreasing priority.
+ * String natives, this method will establish new mappings
+ * for the first of those elements and ignore the rest of them.
+ * DataFlavor key for the mappings
+ * @param natives the String native values for the mappings
+ * @throws NullPointerException if flav or natives is null
+ * or if natives contains null elements
+ *
+ * @see #setFlavorsForNative
+ * @since 1.4
+ */
+ public synchronized void setNativesForFlavor(DataFlavor flavor,
+ String[] natives)
+ {
+ if ((natives == null) || (flavor == null))
+ throw new NullPointerException();
+
+ flavorToNativeMap.remove(flavor);
+ for (int i = 0; i < natives.length; i++)
+ {
+ addUnencodedNativeForFlavor(flavor, natives[i]);
+ }
+ }
+
+ /**
+ * Discards the current mappings for the specified String
+ * native, and creates new mappings to the specified
+ * DataFlavors. Unlike getFlavorsForNative, the
+ * mappings will only be established in one direction, and the natives need
+ * not be encoded. To establish two-way mappings, call
+ * setNativesForFlavor as well. The first
+ * DataFlavor in the array will represent the highest priority
+ * mapping. Subsequent DataFlavors will represent mappings of
+ * decreasing priority.
+ * DataFlavors, this method will establish new mappings
+ * for the first of those elements and ignore the rest of them.
+ * String native key for the mappings
+ * @param flavors the DataFlavor values for the mappings
+ * @throws NullPointerException if nat or flavors is null
+ * or if flavors contains null elements
+ *
+ * @see #setNativesForFlavor
+ * @since 1.4
+ */
+ public synchronized void setFlavorsForNative(String nativeStr,
+ DataFlavor[] flavors)
+ {
+ if ((nativeStr == null) || (flavors == null))
+ throw new NullPointerException();
+
+ nativeToFlavorMap.remove(nativeStr);
+ for (int i = 0; i < flavors.length; i++)
+ {
+ addFlavorForUnencodedNative(nativeStr, flavors[i]);
+ }
+ }
} // class SystemFlavorMap
diff --git a/libjava/classpath/java/beans/DefaultPersistenceDelegate.java b/libjava/classpath/java/beans/DefaultPersistenceDelegate.java
new file mode 100644
index 00000000000..9dd1ae564f7
--- /dev/null
+++ b/libjava/classpath/java/beans/DefaultPersistenceDelegate.java
@@ -0,0 +1,194 @@
+/* DefaultPersistenceDelegate.java
+ Copyright (C) 2005 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.beans;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/** DefaultPersistenceDelegate is a {@link PersistenceDelegate}
+ * implementation that can be used to serialize objects which adhere to the
+ * Java Beans naming convention.null a default instance will be used that
+ * prints the thrown exception to System.err.
+ */
+ public void setExceptionListener(ExceptionListener listener)
+ {
+ exceptionListener = (listener != null) ? listener : new ExceptionListener()
+ {
+ public void exceptionThrown(Exception e)
+ {
+ System.err.println("exception thrown: " + e);
+ e.printStackTrace();
+ }
+ };
+ }
+
+ /**
+ * Returns the currently active {@link ExceptionListener} instance.
+ */
+ public ExceptionListener getExceptionListener()
+ {
+ return exceptionListener;
+ }
+
+ public PersistenceDelegate getPersistenceDelegate(Class type)
+ {
+ // This is not specified but the JDK behaves like this.
+ if (type == null)
+ return fakePersistenceDelegate;
+
+ // Treats all array classes in the same way and assigns
+ // them a shared PersistenceDelegate implementation tailored
+ // for array instantation and initialization.
+ if (type.isArray())
+ return (PersistenceDelegate) delegates.get(Object[].class);
+
+ PersistenceDelegate pd = (PersistenceDelegate) delegates.get(type);
+
+ return (pd != null) ? pd : (PersistenceDelegate) defaultPersistenceDelegate;
+ }
+
+ /**
+ * Sets the {@link PersistenceDelegate} instance for the given class.
+ * NullPointerException if the argument is
+ * null.
+ * static changes to
+ * the {@link PersistenceDelegate}s affect all
+ * {@link Encoder} instances. In this implementation the
+ * access is thread safe.
+ * null if the object has not
+ * been processed yet.
+ * String class acts as an endpoint for the
+ * inherently recursive algorithm of the {@link Encoder}. Therefore instances
+ * of String will always be returned by this method. In other
+ * words the assertion:
+ * assert (anyEncoder.get(anyString) == anyString)
+ *
+ *
+ * null is requested, the result will
+ * always be null.
- **
- **
- ** A final constraint is that event listener classes must extend from EventListener.void return value. Any
- ** parameters and exceptions are allowed. May be public, protected or
- ** package-protected. (Don't ask me why that is, I'm just following the spec.
- ** The only place it is even mentioned is in the Java Beans white paper, and
- ** there it is only implied.)void return value. Must
- ** take exactly one argument, of the listener class's type. May fire either
- ** zero exceptions, or one exception of type java.util.TooManyListenersException.
- ** Must be public.void return value.
- ** Must take exactly one argument, of the listener class's type. May not
- ** fire any exceptions. Must be public.
- **
- ** @param eventSourceClass the class containing the add/remove listener methods.
- ** @param eventSetName the programmatic name of the event set, generally starting
- ** with a lowercase letter (i.e. fooManChu instead of FooManChu). This will be used
- ** to generate the name of the event object as well as the names of the add and
- ** remove methods.
- ** @param listenerType the class containing the event firing method.
- ** @param listenerMethodName the name of the event firing method.
- ** @exception IntrospectionException if listenerType is not an EventListener,
- ** or if methods are not found or are invalid.
- **/
- public EventSetDescriptor(Class eventSourceClass,
- String eventSetName,
- Class listenerType,
- String listenerMethodName) throws IntrospectionException {
- setName(eventSetName);
- if(!java.util.EventListener.class.isAssignableFrom(listenerType)) {
- throw new IntrospectionException("Listener type is not an EventListener.");
- }
-
- String[] names = new String[1];
- names[0] = listenerMethodName;
-
- try {
- eventSetName = Character.toUpperCase(eventSetName.charAt(0)) + eventSetName.substring(1);
- } catch(StringIndexOutOfBoundsException e) {
- eventSetName = "";
- }
-
- findMethods(eventSourceClass,listenerType,names,"add"+eventSetName+"Listener","remove"+eventSetName+"Listener",eventSetName+"Event");
- this.listenerType = listenerType;
- checkAddListenerUnicast();
- if(this.removeListenerMethod.getExceptionTypes().length > 0) {
- throw new IntrospectionException("Listener remove method throws exceptions.");
- }
- }
-
- /** Create a new EventSetDescriptor.
- ** This form of the constructor allows you to specify the names of the methods and adds
- ** no new constraints on top of the rules already described at the top of the class.void <listenerMethodName>(<eventSetName>Event)
- ** (where <eventSetName> has its first character capitalized
- ** by the constructor and the Event is a descendant of
- ** java.util.EventObject) in class listenerType
- ** (any exceptions may be thrown).
- ** Implementation note: Note that there could conceivably be multiple
- ** methods with this type of signature (example: java.util.MouseEvent vs.
- ** my.very.own.MouseEvent). In this implementation, all methods fitting the
- ** description will be put into the EventSetDescriptor, even
- ** though the spec says only one should be chosen (they probably weren't thinking as
- ** pathologically as I was). I don't like arbitrarily choosing things.
- ** If your class has only one such signature, as most do, you'll have no problems.void add<eventSetName>Listener(<listenerType>) and
- ** void remove<eventSetName>Listener(<listenerType>) in
- ** in class eventSourceClass, where
- ** <eventSetName> will have its first letter capitalized.
- ** Standard exception rules (see class description) apply.
+ *
+ *
+ * void return value. Any
+ * parameters and exceptions are allowed. May be public, protected or
+ * package-protected. (Don't ask me why that is, I'm just following the spec.
+ * The only place it is even mentioned is in the Java Beans white paper, and
+ * there it is only implied.)void return value. Must
+ * take exactly one argument, of the listener class's type. May fire either
+ * zero exceptions, or one exception of type
+ * java.util.TooManyListenersException.
+ * Must be public.void return value. Must
+ * take exactly one argument, of the listener class's type. May not fire any
+ * exceptions. Must be public.EventSetDescriptor
+ * This version of the constructor enforces the rules imposed on the methods
+ * described at the top of this class, as well as searching for:
+ *
+ *
+ *
+ * @param eventSourceClass
+ * the class containing the add/remove listener methods.
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu). This will
+ * be used to generate the name of the event object as well as the
+ * names of the add and remove methods.
+ * @param listenerType
+ * the class containing the event firing method.
+ * @param listenerMethodName
+ * the name of the event firing method.
+ * @exception IntrospectionException
+ * if listenerType is not an EventListener, or if methods are not
+ * found or are invalid.
+ */
+ public EventSetDescriptor(Class eventSourceClass, String eventSetName,
+ Class listenerType, String listenerMethodName)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ String[] names = new String[1];
+ names[0] = listenerMethodName;
+
+ try
+ {
+ eventSetName = Character.toUpperCase(eventSetName.charAt(0))
+ + eventSetName.substring(1);
+ }
+ catch (StringIndexOutOfBoundsException e)
+ {
+ eventSetName = "";
+ }
+
+ findMethods(eventSourceClass, listenerType, names,
+ "add" + eventSetName + "Listener",
+ "remove" + eventSetName + "Listener", eventSetName + "Event");
+ this.listenerType = listenerType;
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /**
+ * Creates a new void
+ * <listenerMethodName>(<eventSetName>Event) (where
+ * <eventSetName> has its first character capitalized
+ * by the constructor and the Event is a descendant of
+ * {@link java.util.EventObject}) in class listenerType
+ * (any exceptions may be thrown). Implementation note: Note that
+ * there could conceivably be multiple methods with this type of signature
+ * (example: java.util.MouseEvent vs.
+ * my.very.own.MouseEvent). In this implementation, all
+ * methods fitting the description will be put into the
+ * EventSetDescriptor, even though the spec says only one
+ * should be chosen (they probably weren't thinking as pathologically as I
+ * was). I don't like arbitrarily choosing things. If your class has only one
+ * such signature, as most do, you'll have no problems.void
+ * add<eventSetName>Listener(<listenerType>) and
+ * void remove<eventSetName>Listener(<listenerType>)
+ * in in class eventSourceClass, where
+ * <eventSetName> will have its first letter capitalized.
+ * Standard exception rules (see class description) apply.EventSetDescriptor.
+ *
+ * EventSetDescriptor.
+ *
+ * Class
+ * {@link java.awt.Component#getListeners(Class)} is such a method.
+ * EventSetDescriptor.
+ *
+ * Class
+ * {@link java.awt.Component#getListeners(Class)} is such a method.
+ * EventSetDescriptor.
+ *
+ * EventSetDescriptor.
+ * The methods are, however, checked to ensure that they follow the rules
+ * set forth at the top of the class.
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethods
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ */
+ public EventSetDescriptor(String eventSetName, Class listenerType,
+ Method[] listenerMethods, Method addListenerMethod,
+ Method removeListenerMethod)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ this.listenerMethods = listenerMethods;
+ this.addListenerMethod = addListenerMethod;
+ this.removeListenerMethod = removeListenerMethod;
+ this.listenerType = listenerType;
+ checkMethods();
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /** Creates a new EventSetDescriptor.
+ *
+ * EventSetDescriptor.
+ * The methods are, however, checked to ensure that they follow the rules
+ * set forth at the top of the class.
+ *
+ * @param eventSetName
+ * the programmatic name of the event set, generally starting with a
+ * lowercase letter (i.e. fooManChu instead of FooManChu).
+ * @param listenerType
+ * the class containing the listenerMethods.
+ * @param listenerMethodDescriptors
+ * the event firing methods.
+ * @param addListenerMethod
+ * the add listener method.
+ * @param removeListenerMethod
+ * the remove listener method.
+ * @exception IntrospectionException
+ * if the listenerType is not an EventListener, or any of the
+ * methods are invalid.
+ */
+ public EventSetDescriptor(String eventSetName, Class listenerType,
+ MethodDescriptor[] listenerMethodDescriptors,
+ Method addListenerMethod,
+ Method removeListenerMethod)
+ throws IntrospectionException
+ {
+ setName(eventSetName);
+ if (!java.util.EventListener.class.isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException(
+ "Listener type is not an EventListener.");
+ }
+
+ this.listenerMethodDescriptors = listenerMethodDescriptors;
+ this.listenerMethods = new Method[listenerMethodDescriptors.length];
+ for (int i = 0; i < this.listenerMethodDescriptors.length; i++)
+ {
+ this.listenerMethods[i]
+ = this.listenerMethodDescriptors[i].getMethod();
+ }
+
+ this.addListenerMethod = addListenerMethod;
+ this.removeListenerMethod = removeListenerMethod;
+ this.listenerType = listenerType;
+ checkMethods();
+ checkAddListenerUnicast();
+ if (this.removeListenerMethod.getExceptionTypes().length > 0)
+ {
+ throw new IntrospectionException(
+ "Listener remove method throws exceptions.");
+ }
+ }
+
+ /** Returns the class that contains the event firing methods.
+ */
+ public Class getListenerType()
+ {
+ return listenerType;
+ }
+
+ /** Returns the event firing methods.
+ */
+ public Method[] getListenerMethods()
+ {
+ return listenerMethods;
+ }
+
+ /** Returns the event firing methods as {@link MethodDescriptor}.
+ */
+ public MethodDescriptor[] getListenerMethodDescriptors()
+ {
+ if (listenerMethodDescriptors == null)
+ {
+ listenerMethodDescriptors
+ = new MethodDescriptor[listenerMethods.length];
+
+ for (int i = 0; i < listenerMethods.length; i++)
+ {
+ listenerMethodDescriptors[i]
+ = new MethodDescriptor(listenerMethods[i]);
+ }
+ }
+
+ return listenerMethodDescriptors;
+ }
+
+ /** Returns the add listener method.
+ */
+ public Method getAddListenerMethod()
+ {
+ return addListenerMethod;
+ }
+
+ /* Returns the remove listener method.
+ */
+ public Method getRemoveListenerMethod()
+ {
+ return removeListenerMethod;
+ }
+
+ /**
+ * Returns the method that retrieves the listeners or null if
+ * it does not exist.
+ */
+ public Method getGetListenerMethod()
+ {
+ return getListenerMethod;
+ }
+
+ /** Sets whether or not multiple listeners may be added.
+ *
+ * @param unicast
+ * whether or not multiple listeners may be added.
+ */
+ public void setUnicast(boolean unicast)
+ {
+ this.unicast = unicast;
+ }
+
+ /** Returns whether or not multiple listeners may be added.
+ * (Defaults to false.)
+ */
+ public boolean isUnicast()
+ {
+ return unicast;
+ }
+
+ /** Sets whether or not this is in the default event set.
+ *
+ * @param inDefaultEventSet
+ * whether this is in the default event set.
+ */
+ public void setInDefaultEventSet(boolean inDefaultEventSet)
+ {
+ this.inDefaultEventSet = inDefaultEventSet;
+ }
+
+ /** Returns whether or not this is in the default event set.
+ * (Defaults to true.)
+ */
+ public boolean isInDefaultEventSet()
+ {
+ return inDefaultEventSet;
+ }
+
+ private void checkAddListenerUnicast() throws IntrospectionException
+ {
+ Class[] addListenerExceptions = this.addListenerMethod.getExceptionTypes();
+ if (addListenerExceptions.length > 1)
+ {
+ throw new IntrospectionException(
+ "Listener add method throws too many exceptions.");
+ }
+ else if (addListenerExceptions.length == 1
+ && !java.util.TooManyListenersException.class
+ .isAssignableFrom(addListenerExceptions[0]))
+ {
+ throw new IntrospectionException(
+ "Listener add method throws too many exceptions.");
+ }
+ }
+
+ private void checkMethods() throws IntrospectionException
+ {
+ if (!addListenerMethod.getDeclaringClass()
+ .isAssignableFrom(removeListenerMethod.getDeclaringClass())
+ && !removeListenerMethod.getDeclaringClass()
+ .isAssignableFrom(addListenerMethod.getDeclaringClass()))
+ {
+ throw new IntrospectionException(
+ "add and remove listener methods do not come from the"
+ + " same class. This is bad.");
+ }
+ if (!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
+ || addListenerMethod.getParameterTypes().length != 1
+ || !listenerType.equals(addListenerMethod.getParameterTypes()[0])
+ || !Modifier.isPublic(addListenerMethod.getModifiers()))
+ {
+ throw new IntrospectionException("Add Listener Method invalid.");
+ }
+ if (!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE)
+ || removeListenerMethod.getParameterTypes().length != 1
+ || !listenerType.equals(removeListenerMethod.getParameterTypes()[0])
+ || removeListenerMethod.getExceptionTypes().length > 0
+ || !Modifier.isPublic(removeListenerMethod.getModifiers()))
+ {
+ throw new IntrospectionException("Remove Listener Method invalid.");
+ }
+
+ for (int i = 0; i < listenerMethods.length; i++)
+ {
+ if (!listenerMethods[i].getReturnType().equals(java.lang.Void.TYPE)
+ || Modifier.isPrivate(listenerMethods[i].getModifiers()))
+ {
+ throw new IntrospectionException("Event Method "
+ + listenerMethods[i].getName()
+ + " non-void or private.");
+ }
+ if (!listenerMethods[i].getDeclaringClass()
+ .isAssignableFrom(listenerType))
+ {
+ throw new IntrospectionException("Event Method "
+ + listenerMethods[i].getName()
+ + " not from class "
+ + listenerType.getName());
+ }
+ }
+ }
+
+ private void findMethods(Class eventSourceClass, Class listenerType,
+ String listenerMethodNames[],
+ String addListenerMethodName,
+ String removeListenerMethodName,
+ String absurdEventClassCheckName)
+ throws IntrospectionException
+ {
+
+ /* Find add listener method and remove listener method. */
+ Class[] listenerArgList = new Class[1];
+ listenerArgList[0] = listenerType;
+ try
+ {
+ this.addListenerMethod
+ = eventSourceClass.getMethod(addListenerMethodName,
+ listenerArgList);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "SecurityException trying to access method "
+ + addListenerMethodName + ".");
+ }
+ catch (NoSuchMethodException E)
+ {
+ throw new IntrospectionException("Could not find method "
+ + addListenerMethodName + ".");
+ }
+
+ if (this.addListenerMethod == null
+ || !this.addListenerMethod.getReturnType().equals(java.lang.Void.TYPE))
+ {
+ throw new IntrospectionException(
+ "Add listener method does not exist, is not public,"
+ + " or is not void.");
+ }
+
+ try
+ {
+ this.removeListenerMethod
+ = eventSourceClass.getMethod(removeListenerMethodName,
+ listenerArgList);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "SecurityException trying to access method "
+ + removeListenerMethodName + ".");
+ }
+ catch (NoSuchMethodException E)
+ {
+ throw new IntrospectionException("Could not find method "
+ + removeListenerMethodName + ".");
+ }
+ if (this.removeListenerMethod == null
+ || !this.removeListenerMethod.getReturnType()
+ .equals(java.lang.Void.TYPE))
+ {
+ throw new IntrospectionException(
+ "Remove listener method does not exist, is not public,"
+ + " or is not void.");
+ }
+
+ /* Find the listener methods. */
+ Method[] methods;
+ try
+ {
+ methods = ClassHelper.getAllMethods(listenerType);
+ }
+ catch (SecurityException E)
+ {
+ throw new IntrospectionException(
+ "Security: You cannot access fields in this class.");
+ }
+
+ Vector chosenMethods = new Vector();
+ boolean[] listenerMethodFound = new boolean[listenerMethodNames.length];
+ for (int i = 0; i < methods.length; i++)
+ {
+ if (Modifier.isPrivate(methods[i].getModifiers()))
+ {
+ continue;
+ }
+ Method currentMethod = methods[i];
+ Class retval = currentMethod.getReturnType();
+ if (retval.equals(java.lang.Void.TYPE))
+ {
+ for (int j = 0; j < listenerMethodNames.length; j++)
+ {
+ if (currentMethod.getName().equals(listenerMethodNames[j])
+ && (absurdEventClassCheckName == null
+ || (currentMethod.getParameterTypes().length == 1
+ && ((currentMethod.getParameterTypes()[0])
+ .getName().equals(absurdEventClassCheckName)
+ || (currentMethod.getParameterTypes()[0])
+ .getName().endsWith("." + absurdEventClassCheckName)))))
+ {
+ chosenMethods.addElement(currentMethod);
+ listenerMethodFound[j] = true;
+ }
+ }
+ }
+ }
+
+ /* Make sure we found all the methods we were looking for. */
+ for (int i = 0; i < listenerMethodFound.length; i++)
+ {
+ if (!listenerMethodFound[i])
+ {
+ throw new IntrospectionException("Could not find event method "
+ + listenerMethodNames[i]);
+ }
+ }
+
+ /* Now that we've chosen the listener methods we want, store them. */
+ this.listenerMethods = new Method[chosenMethods.size()];
+ for (int i = 0; i < chosenMethods.size(); i++)
+ {
+ this.listenerMethods[i] = (Method) chosenMethods.elementAt(i);
+ }
+ }
+
}
diff --git a/libjava/classpath/java/beans/Expression.java b/libjava/classpath/java/beans/Expression.java
index d92cb7284aa..b327864d95f 100644
--- a/libjava/classpath/java/beans/Expression.java
+++ b/libjava/classpath/java/beans/Expression.java
@@ -35,16 +35,19 @@ 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;
/**
- * class Expression
- *
- * An Expression captures the execution of an object method that
- * returns a value. It stores an object, the method to call, and the
- * arguments to pass to the method.
- *
+ * flag set to
+ * {@link #IGNORE_IMMEDIATE_BEANINFO} will let it use all
+ * explicit BeanInfo classes for the beans superclasses
+ * but not for the bean class itself. Furthermore eventset,
+ * property and method information is retrieved by introspection
+ * if the explicit BeanInfos did not provide such data
+ * (ie. return null on {@link BeanInfo.getMethodDescriptors},
+ * {@link BeanInfo.getEventSetDescriptors} and
+ * {@link BeanInfo.getPropertyDescriptors}.)
+ * flag
+ *
+ * flag is interpreted
+ * as {@link #IGNORE_ALL_BEANINFO}BeanInfo classes.
+ * @return A BeanInfo object describing the class.
+ * @throws IntrospectionException If something goes wrong while retrieving
+ * the bean data.
+ */
+ public static BeanInfo getBeanInfo(Class beanClass, int flag)
+ throws IntrospectionException
+ {
+ IntrospectionIncubator ii;
+ BeanInfoEmbryo infoEmbryo;
+
+ switch(flag)
+ {
+ case USE_ALL_BEANINFO:
+ return getBeanInfo(beanClass);
+ case IGNORE_IMMEDIATE_BEANINFO:
+ Class superclass = beanClass.getSuperclass();
+ ExplicitInfo explicit = new ExplicitInfo(superclass, null);
+
+ ii = new IntrospectionIncubator();
+ if (explicit.explicitEventSetDescriptors != null)
+ ii.setEventStopClass(superclass);
+
+ if (explicit.explicitMethodDescriptors != null)
+ ii.setMethodStopClass(superclass);
+
+ if (explicit.explicitPropertyDescriptors != null)
+ ii.setPropertyStopClass(superclass);
+
+ ii.addMethods(beanClass.getMethods());
+
+ infoEmbryo = ii.getBeanInfoEmbryo();
+ merge(infoEmbryo, explicit);
+
+ infoEmbryo.setBeanDescriptor(new BeanDescriptor(beanClass, null));
+
+ return infoEmbryo.getBeanInfo();
+ case IGNORE_ALL_BEANINFO:
+ default:
+ ii = new IntrospectionIncubator();
+ ii.addMethods(beanClass.getMethods());
+ infoEmbryo = ii.getBeanInfoEmbryo();
+ infoEmbryo.setBeanDescriptor(new BeanDescriptor(beanClass, null));
+
+ return infoEmbryo.getBeanInfo();
+ }
+ }
/**
* Flush all of the Introspector's internal caches.
@@ -244,6 +320,69 @@ public class Introspector {
}
}
+ /** Adds all explicity given bean info data to the introspected
+ * data.
+ *
+ * @param infoEmbryo Bean info data retrieved by introspection.
+ * @param explicit Bean info data retrieved by BeanInfo classes.
+ */
+ private static void merge(BeanInfoEmbryo infoEmbryo, ExplicitInfo explicit)
+ {
+ PropertyDescriptor[] p = explicit.explicitPropertyDescriptors;
+ if(p!=null)
+ {
+ for(int i=0;iPersistenceDelegate describes how a another object
+ * has to constructed and transformed in order to create a complete
+ * replicate.
For custom classes you will need to implement
+ * PersistenceDelegate in a way that is suitable for them.
+ * To make use of the implementation you have to register it with an
+ * {@link Encoder} using the {Encoder#setPersistenceDelegate} method.
true if there are listeners on all
diff --git a/libjava/classpath/java/beans/Statement.java b/libjava/classpath/java/beans/Statement.java
index 8e916a286be..62a5ad7b6f8 100644
--- a/libjava/classpath/java/beans/Statement.java
+++ b/libjava/classpath/java/beans/Statement.java
@@ -1,4 +1,4 @@
-/* java.beans.Statement
+/* Statement.java
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,32 +42,26 @@ import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.WeakHashMap;
-
/**
- * class Statement
- *
- * A Statement captures the execution of an object method. It stores
+ * A Statement captures the execution of an object method. It stores * the object, the method to call, and the arguments to the method and * provides the ability to execute the method on the object, using the - * provided arguments. + * provided arguments.
* + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Robert Schuster (robertschuster@fsfe.org) * @since 1.4 */ public class Statement { - /** Nested map for the relation between a class, its instances and their - * names. - */ - private static HashMap classMaps = new HashMap(); - private Object target; private String methodName; private Object[] arguments; - // One or the other of these will get a value after execute is - // called once, but not both. + /** + * One or the other of these will get a value after execute is + * called once, but not both. + */ private transient Method method; private transient Constructor ctor; @@ -87,76 +81,44 @@ public class Statement this.target = target; this.methodName = methodName; this.arguments = (arguments != null) ? arguments : new Object[0]; - storeTargetName(target); - } - - /** Creates a name for the target instance or does nothing if the object's - * name is already known. This makes sure that there *is* a name for every - * target instance. - */ - private static synchronized void storeTargetName(Object obj) - { - Class klass = obj.getClass(); - WeakHashMap names = (WeakHashMap) classMaps.get(klass); - - if ( names == null ) - { - names = new WeakHashMap(); - - names.put(obj, - ( klass == String.class ? ("\"" + obj + "\"") : - (klass.getName() + names.size()) )); - - classMaps.put(klass, names); - - return; - } - - String targetName = (String) names.get(obj); - if ( targetName == null ) - { - names.put(obj, - ( klass == String.class ? ("\"" + obj + "\"") : - (klass.getName() + names.size()) )); - } - - // Nothing to do. The given object was already stored. } /** * Execute the statement. * - * Finds the specified method in the target object and calls it with - * the arguments given in the constructor. + *Finds the specified method in the target object and calls it with + * the arguments given in the constructor.
* - * The most specific method according to the JLS(15.11) is used when - * there are multiple methods with the same name. + *The most specific method according to the JLS(15.11) is used when + * there are multiple methods with the same name.
* - * Execute performs some special handling for methods and + *Execute performs some special handling for methods and * parameters: + *
The Sun spec doesn't deal with overloading between int and * Integer carefully. If there are two methods, one that takes an * Integer and the other taking an int, the method chosen is not * specified, and can depend on the order in which the methods are - * declared in the source file. + * declared in the source file.
* * @throws Exception if an exception occurs while locating or * invoking the method. @@ -178,8 +140,10 @@ public class Statement Integer.TYPE, Long.TYPE, Short.TYPE }; - // Given a wrapper class, return the native class for it. For - // example, if c is Integer, Integer.TYPE is returned. + /** Given a wrapper class, return the native class for it. + *For example, if c is Integer,
+ * Integer.TYPE is returned.
true if all args can be assigned to
+ * params, false otherwise.
+ *
+ * Arrays are guaranteed to be the same length.
+ */ private boolean compatible(Class[] params, Class[] args) { for (int i = 0; i < params.length; i++) { - // Treat Integer like int if appropriate + // Argument types are derived from argument values. If one of them was + // null then we cannot deduce its type. However null can be assigned to + // any type. + if (args[i] == null) + continue; + + // Treat Integer like int if appropriate Class nativeType = unwrap(args[i]); if (nativeType != null && params[i].isPrimitive() && params[i].isAssignableFrom(nativeType)) @@ -208,14 +181,15 @@ public class Statement } /** - * Return true if the method arguments in first are more specific - * than the method arguments in second, i.e. all args in first can - * be assigned to those in second. + * Returnstrue if the method arguments in first are
+ * more specific than the method arguments in second, i.e. all
+ * arguments in first can be assigned to those in
+ * second.
*
- * A method is more specific if all parameters can also be fed to
+ * A method is more specific if all parameters can also be fed to * the less specific method, because, e.g. the less specific method * accepts a base class of the equivalent argument for the more - * specific one. + * specific one.
* * @param first aClass[] value
* @param second a Class[] value
@@ -238,8 +212,11 @@ public class Statement
? (Class) target : target.getClass();
Object args[] = (arguments == null) ? new Object[0] : arguments;
Class argTypes[] = new Class[args.length];
+
+ // Retrieve type or use null if the argument is null. The null argument
+ // type is later used in compatible().
for (int i = 0; i < args.length; i++)
- argTypes[i] = args[i].getClass();
+ argTypes[i] = (args[i] != null) ? args[i].getClass() : null;
if (target.getClass().isArray())
{
@@ -333,7 +310,29 @@ public class Statement
}
if (method == null)
throw new NoSuchMethodException("No matching method for statement " + toString());
+
+ // If we were calling Class.forName(String) we intercept and call the
+ // forName-variant that allows a ClassLoader argument. We take the
+ // system classloader (aka application classloader) here to make sure
+ // that application defined classes can be resolved. If we would not
+ // do that the Class.forName implementation would use the class loader
+ // of java.beans.Statement which is File object to represent
* a file corresponding to the specified file: protocol URI.
*
- * @param uri The uri.
+ * @param uri The URI
+ * @throws IllegalArgumentException if the URI is not hierarchical
*/
public File(URI uri)
{
@@ -406,7 +407,11 @@ public class File implements Serializable, Comparable
if (!uri.getScheme().equals("file"))
throw new IllegalArgumentException("invalid uri protocol");
- path = normalizePath(uri.getPath());
+ String name = uri.getPath();
+ if (name == null)
+ throw new IllegalArgumentException("URI \"" + uri
+ + "\" is not hierarchical");
+ path = normalizePath(name);
}
/**
diff --git a/libjava/classpath/java/io/InputStreamReader.java b/libjava/classpath/java/io/InputStreamReader.java
index 57cdc53ed22..ef8fd4542db 100644
--- a/libjava/classpath/java/io/InputStreamReader.java
+++ b/libjava/classpath/java/io/InputStreamReader.java
@@ -230,6 +230,8 @@ public class InputStreamReader extends Reader
* Creates an InputStreamReader that uses a decoder of the given
* charset to decode the bytes in the InputStream into
* characters.
+ *
+ * @since 1.5
*/
public InputStreamReader(InputStream in, Charset charset) {
this.in = in;
@@ -244,6 +246,8 @@ public class InputStreamReader extends Reader
/**
* Creates an InputStreamReader that uses the given charset decoder
* to decode the bytes in the InputStream into characters.
+ *
+ * @since 1.5
*/
public InputStreamReader(InputStream in, CharsetDecoder decoder) {
this.in = in;
diff --git a/libjava/classpath/java/io/ObjectInputStream.java b/libjava/classpath/java/io/ObjectInputStream.java
index 98a11dae3e1..750c6989f25 100644
--- a/libjava/classpath/java/io/ObjectInputStream.java
+++ b/libjava/classpath/java/io/ObjectInputStream.java
@@ -50,7 +50,6 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.util.Arrays;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.TreeSet;
diff --git a/libjava/classpath/java/io/ObjectOutputStream.java b/libjava/classpath/java/io/ObjectOutputStream.java
index 573b9cfa1de..961d5e3099f 100644
--- a/libjava/classpath/java/io/ObjectOutputStream.java
+++ b/libjava/classpath/java/io/ObjectOutputStream.java
@@ -442,6 +442,11 @@ public class ObjectOutputStream extends OutputStream
realOutput.writeByte(flags);
ObjectStreamField[] fields = osc.fields;
+
+ if (fields == ObjectStreamClass.INVALID_FIELDS)
+ throw new InvalidClassException
+ (osc.getName(), "serialPersistentFields is invalid");
+
realOutput.writeShort(fields.length);
ObjectStreamField field;
diff --git a/libjava/classpath/java/io/ObjectStreamClass.java b/libjava/classpath/java/io/ObjectStreamClass.java
index 975dbfc66d0..203e4a5abaa 100644
--- a/libjava/classpath/java/io/ObjectStreamClass.java
+++ b/libjava/classpath/java/io/ObjectStreamClass.java
@@ -63,6 +63,8 @@ import java.util.Vector;
public class ObjectStreamClass implements Serializable
{
+ static final ObjectStreamField[] INVALID_FIELDS = new ObjectStreamField[0];
+
/**
* Returns the ObjectStreamClass for cl.
* If cl is null, or is not Serializable,
@@ -71,6 +73,11 @@ public class ObjectStreamClass implements Serializable
* same ObjectStreamClass object and no recalculation
* will be done.
*
+ * Warning: If this class contains an invalid serialPersistentField arrays
+ * lookup will not throw anything. However {@link #getFields()} will return
+ * an empty array and {@link java.io.ObjectOutputStream#writeObject} will throw an
+ * {@link java.io.InvalidClassException}.
+ *
* @see java.io.Serializable
*/
public static ObjectStreamClass lookup(Class cl)
@@ -148,6 +155,8 @@ public class ObjectStreamClass implements Serializable
* Returns the serializable (non-static and non-transient) Fields
* of the class represented by this ObjectStreamClass. The Fields
* are sorted by name.
+ * If fields were obtained using serialPersistentFields and this array
+ * is faulty then the returned array of this method will be empty.
*
* @return the fields.
*/
@@ -608,6 +617,28 @@ outer:
fields = getSerialPersistentFields(cl);
if (fields != null)
{
+ ObjectStreamField[] fieldsName = new ObjectStreamField[fields.length];
+ System.arraycopy(fields, 0, fieldsName, 0, fields.length);
+
+ Arrays.sort (fieldsName, new Comparator() {
+ public int compare(Object o1, Object o2)
+ {
+ ObjectStreamField f1 = (ObjectStreamField)o1;
+ ObjectStreamField f2 = (ObjectStreamField)o2;
+
+ return f1.getName().compareTo(f2.getName());
+ }
+ });
+
+ for (int i=1; i < fields.length; i++)
+ {
+ if (fieldsName[i-1].getName().equals(fieldsName[i].getName()))
+ {
+ fields = INVALID_FIELDS;
+ return;
+ }
+ }
+
Arrays.sort (fields);
// Retrieve field reference.
for (int i=0; i < fields.length; i++)
diff --git a/libjava/classpath/java/io/OutputStreamWriter.java b/libjava/classpath/java/io/OutputStreamWriter.java
index 29fb631faf4..572683834be 100644
--- a/libjava/classpath/java/io/OutputStreamWriter.java
+++ b/libjava/classpath/java/io/OutputStreamWriter.java
@@ -213,6 +213,8 @@ public class OutputStreamWriter extends Writer
*
* @param out The OutputStream to write to
* @param cs The Charset of the encoding to use
+ *
+ * @since 1.5
*/
public OutputStreamWriter(OutputStream out, Charset cs)
{
@@ -230,6 +232,8 @@ public class OutputStreamWriter extends Writer
*
* @param out The OutputStream to write to
* @param enc The CharsetEncoder to encode the output with
+ *
+ * @since 1.5
*/
public OutputStreamWriter(OutputStream out, CharsetEncoder enc)
{
diff --git a/libjava/classpath/java/io/PrintStream.java b/libjava/classpath/java/io/PrintStream.java
index 8e50559b310..99af25583b0 100644
--- a/libjava/classpath/java/io/PrintStream.java
+++ b/libjava/classpath/java/io/PrintStream.java
@@ -1,5 +1,6 @@
/* PrintStream.java -- OutputStream for printing output
- Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +39,8 @@ exception statement from your version. */
package java.io;
+import gnu.classpath.SystemProperties;
+
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
* "The Java Language Specification", ISBN 0-201-63451-1
* Status: Believed complete and correct to 1.3
@@ -64,7 +67,7 @@ public class PrintStream extends FilterOutputStream
// Line separator string.
private static final char[] line_separator
- = System.getProperty("line.separator").toCharArray();
+ = SystemProperties.getProperty("line.separator").toCharArray();
/**
* Encoding name
@@ -112,7 +115,7 @@ public class PrintStream extends FilterOutputStream
super (out);
try {
- this.encoding = System.getProperty("file.encoding");
+ this.encoding = SystemProperties.getProperty("file.encoding");
} catch (SecurityException e){
this.encoding = "ISO8859_1";
} catch (IllegalArgumentException e){
diff --git a/libjava/classpath/java/io/RandomAccessFile.java b/libjava/classpath/java/io/RandomAccessFile.java
index 23be5a31947..84ee5dec01e 100644
--- a/libjava/classpath/java/io/RandomAccessFile.java
+++ b/libjava/classpath/java/io/RandomAccessFile.java
@@ -124,7 +124,10 @@ public class RandomAccessFile implements DataOutput, DataInput
ch = FileChannelImpl.create(file, fdmode);
fd = new FileDescriptor(ch);
- out = new DataOutputStream (new FileOutputStream (fd));
+ if ((fdmode & FileChannelImpl.WRITE) != 0)
+ out = new DataOutputStream (new FileOutputStream (fd));
+ else
+ out = null;
in = new DataInputStream (new FileInputStream (fd));
}
@@ -766,6 +769,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public void write (int oneByte) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.write(oneByte);
}
@@ -777,6 +783,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public void write (byte[] buffer) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.write(buffer);
}
@@ -792,6 +801,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public void write (byte[] buffer, int offset, int len) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.write (buffer, offset, len);
}
@@ -806,6 +818,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeBoolean (boolean val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeBoolean(val);
}
@@ -820,6 +835,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeByte (int val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeByte(val);
}
@@ -834,6 +852,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeShort (int val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeShort(val);
}
@@ -848,6 +869,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeChar (int val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeChar(val);
}
@@ -861,6 +885,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeInt (int val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeInt(val);
}
@@ -874,6 +901,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeLong (long val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeLong(val);
}
@@ -893,6 +923,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeFloat (float val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeFloat(val);
}
@@ -913,6 +946,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeDouble (double val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeDouble(val);
}
@@ -927,6 +963,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeBytes (String val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeBytes(val);
}
@@ -941,6 +980,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeChars (String val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeChars(val);
}
@@ -975,6 +1017,9 @@ public class RandomAccessFile implements DataOutput, DataInput
*/
public final void writeUTF (String val) throws IOException
{
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
out.writeUTF(val);
}
diff --git a/libjava/classpath/java/io/StreamTokenizer.java b/libjava/classpath/java/io/StreamTokenizer.java
index bd7773b1990..b4695ab3d09 100644
--- a/libjava/classpath/java/io/StreamTokenizer.java
+++ b/libjava/classpath/java/io/StreamTokenizer.java
@@ -550,6 +550,12 @@ public class StreamTokenizer
/**
* This method sets the numeric attribute on the characters '0' - '9' and
* the characters '.' and '-'.
+ * When this method is used, the result of giving other attributes
+ * (whitespace, quote, or comment) to the numeric characters may
+ * vary depending on the implementation. For example, if
+ * parseNumbers() and then whitespaceChars('1', '1') are called,
+ * this implementation reads "121" as 2, while some other implementation
+ * will read it as 21.
*/
public void parseNumbers()
{
diff --git a/libjava/classpath/java/lang/Character.java b/libjava/classpath/java/lang/Character.java
index 78db41ef216..3c88ff805c7 100644
--- a/libjava/classpath/java/lang/Character.java
+++ b/libjava/classpath/java/lang/Character.java
@@ -2410,11 +2410,11 @@ public final class Character implements Serializable, Comparable
{
// Write second char first to cause IndexOutOfBoundsException
// immediately.
- dst[dstIndex + 1] = (char) ((codePoint & 0x3ff)
- + (int) MIN_LOW_SURROGATE );
- dst[dstIndex] = (char) ((codePoint >> 10) + (int) MIN_HIGH_SURROGATE);
+ final int cp2 = codePoint - 0x10000;
+ dst[dstIndex + 1] = (char) ((cp2 % 0x400) + (int) MIN_LOW_SURROGATE);
+ dst[dstIndex] = (char) ((cp2 / 0x400) + (int) MIN_HIGH_SURROGATE);
result = 2;
- }
+ }
else
{
dst[dstIndex] = (char) codePoint;
@@ -2523,7 +2523,8 @@ public final class Character implements Serializable, Comparable
*/
public static int toCodePoint(char high, char low)
{
- return ((high - MIN_HIGH_SURROGATE) << 10) + (low - MIN_LOW_SURROGATE);
+ return ((high - MIN_HIGH_SURROGATE) * 0x400) +
+ (low - MIN_LOW_SURROGATE) + 0x10000;
}
/**
diff --git a/libjava/classpath/java/lang/Class.java b/libjava/classpath/java/lang/Class.java
index 726c794a413..c4235e6808c 100644
--- a/libjava/classpath/java/lang/Class.java
+++ b/libjava/classpath/java/lang/Class.java
@@ -583,8 +583,7 @@ public final class Class implements Serializable
/**
* Returns the Package in which this class is defined
* Returns null when this information is not available from the
- * classloader of this class or when the classloader of this class
- * is null.
+ * classloader of this class.
*
* @return the package for this class, if it is available
* @since 1.2
@@ -837,7 +836,10 @@ public final class Class implements Serializable
*/
public int getModifiers()
{
- return VMClass.getModifiers (this, false);
+ int mod = VMClass.getModifiers (this, false);
+ return (mod & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE |
+ Modifier.FINAL | Modifier.STATIC | Modifier.ABSTRACT |
+ Modifier.INTERFACE));
}
/**
diff --git a/libjava/classpath/java/lang/Double.java b/libjava/classpath/java/lang/Double.java
index 26b398bb695..03c56068921 100644
--- a/libjava/classpath/java/lang/Double.java
+++ b/libjava/classpath/java/lang/Double.java
@@ -172,6 +172,81 @@ public final class Double extends Number implements Comparable
return VMDouble.toString(d, false);
}
+ /**
+ * Convert a double value to a hexadecimal string. This converts as
+ * follows:
+ * Double object wrapping the value.
* In contrast to the Double constructor, this method
diff --git a/libjava/classpath/java/lang/Float.java b/libjava/classpath/java/lang/Float.java
index eef34a0abeb..dcd5b221197 100644
--- a/libjava/classpath/java/lang/Float.java
+++ b/libjava/classpath/java/lang/Float.java
@@ -182,6 +182,83 @@ public final class Float extends Number implements Comparable
return VMDouble.toString(f, true);
}
+ /**
+ * Convert a float value to a hexadecimal string. This converts as
+ * follows:
+ * Float object using the String.
*
diff --git a/libjava/classpath/java/lang/InheritableThreadLocal.java b/libjava/classpath/java/lang/InheritableThreadLocal.java
index 69ff6138dc6..b9c7624ef44 100644
--- a/libjava/classpath/java/lang/InheritableThreadLocal.java
+++ b/libjava/classpath/java/lang/InheritableThreadLocal.java
@@ -1,5 +1,5 @@
/* InheritableThreadLocal -- a ThreadLocal which inherits values across threads
- Copyright (C) 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,8 +37,9 @@ exception statement from your version. */
package java.lang;
+import gnu.java.util.WeakIdentityHashMap;
+
import java.util.Iterator;
-import java.util.WeakHashMap;
/**
* A ThreadLocal whose value is inherited by child Threads. The value of the
@@ -98,15 +99,15 @@ public class InheritableThreadLocal extends ThreadLocal
Iterator keys = parentThread.locals.keySet().iterator();
while (keys.hasNext())
{
- Key key = (Key)keys.next();
- if (key.get() instanceof InheritableThreadLocal)
+ Object key = keys.next();
+ if (key instanceof InheritableThreadLocal)
{
- InheritableThreadLocal local = (InheritableThreadLocal)key.get();
+ InheritableThreadLocal local = (InheritableThreadLocal)key;
Object parentValue = parentThread.locals.get(key);
Object childValue = local.childValue(parentValue == NULL
? null : parentValue);
if (childThread.locals == null)
- childThread.locals = new WeakHashMap();
+ childThread.locals = new WeakIdentityHashMap();
childThread.locals.put(key, (childValue == null
? NULL : childValue));
}
diff --git a/libjava/classpath/java/lang/SecurityManager.java b/libjava/classpath/java/lang/SecurityManager.java
index 26d56a64bf3..30ee1be086f 100644
--- a/libjava/classpath/java/lang/SecurityManager.java
+++ b/libjava/classpath/java/lang/SecurityManager.java
@@ -41,9 +41,6 @@ package java.lang;
import gnu.classpath.VMStackWalker;
import java.awt.AWTPermission;
-import java.awt.Frame;
-import java.awt.Toolkit;
-import java.awt.Window;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -424,7 +421,7 @@ public class SecurityManager
public void checkAccess(Thread thread)
{
if (thread.getThreadGroup() != null
- && thread.getThreadGroup().getParent() != null)
+ && thread.getThreadGroup().getParent() == null)
checkPermission(new RuntimePermission("modifyThread"));
}
@@ -457,7 +454,7 @@ public class SecurityManager
*/
public void checkAccess(ThreadGroup g)
{
- if (g.getParent() != null)
+ if (g.getParent() == null)
checkPermission(new RuntimePermission("modifyThreadGroup"));
}
@@ -837,7 +834,7 @@ public class SecurityManager
* @param window the window to create
* @return true if there is permission to show the window without warning
* @throws NullPointerException if window is null
- * @see Window#Window(Frame)
+ * @see java.awt.Window#Window(java.awt.Frame)
*/
public boolean checkTopLevelWindow(Object window)
{
@@ -862,7 +859,7 @@ public class SecurityManager
* an exception.
*
* @throws SecurityException if permission is denied
- * @see Toolkit#getPrintJob(Frame, String, Properties)
+ * @see java.awt.Toolkit#getPrintJob(java.awt.Frame, String, Properties)
* @since 1.1
*/
public void checkPrintJobAccess()
@@ -878,7 +875,7 @@ public class SecurityManager
* rather than throwing an exception.
*
* @throws SecurityException if permission is denied
- * @see Toolkit#getSystemClipboard()
+ * @see java.awt.Toolkit#getSystemClipboard()
* @since 1.1
*/
public void checkSystemClipboardAccess()
@@ -894,7 +891,7 @@ public class SecurityManager
* rather than throwing an exception.
*
* @throws SecurityException if permission is denied
- * @see Toolkit#getSystemEventQueue()
+ * @see java.awt.Toolkit#getSystemEventQueue()
* @since 1.1
*/
public void checkAwtEventQueueAccess()
diff --git a/libjava/classpath/java/lang/StackTraceElement.java b/libjava/classpath/java/lang/StackTraceElement.java
index 6dd4d8532e8..cf4d1c76f4d 100644
--- a/libjava/classpath/java/lang/StackTraceElement.java
+++ b/libjava/classpath/java/lang/StackTraceElement.java
@@ -49,7 +49,7 @@ import java.io.Serializable;
* @author Mark Wielaard (mark@klomp.org)
* @author Eric Blake (ebb9@email.byu.edu)
* @since 1.4
- * @status updated to 1.4
+ * @status updated to 1.5
*/
public final class StackTraceElement implements Serializable
{
@@ -111,6 +111,26 @@ public final class StackTraceElement implements Serializable
this.isNative = isNative;
}
+ /**
+ * Create a new StackTraceElement representing a given source location.
+ *
+ * @param className the fully qualified name of the class
+ * @param methodName the name of the method
+ * @param fileName the name of the file, null if unknown
+ * @param lineNumber the line in the file, negative if unknown, or -2
+ * if this method is native
+ *
+ * @since 1.5
+ */
+ public StackTraceElement(String className, String methodName, String fileName,
+ int lineNumber)
+ {
+ this(fileName, lineNumber, className, methodName, lineNumber == -2);
+ // The public constructor doesn't allow certain values to be null.
+ if (className == null || methodName == null)
+ throw new NullPointerException("invalid argument to constructor");
+ }
+
/**
* Returns the name of the file, or null if unknown. This is usually
* obtained from the SourceFile attribute of the class file
diff --git a/libjava/classpath/java/lang/String.java b/libjava/classpath/java/lang/String.java
index 369d8085a02..231afc77b92 100644
--- a/libjava/classpath/java/lang/String.java
+++ b/libjava/classpath/java/lang/String.java
@@ -273,7 +273,8 @@ public final class String implements Serializable, Comparable, CharSequence
throw new StringIndexOutOfBoundsException("offset: " + offset);
if (count < 0)
throw new StringIndexOutOfBoundsException("count: " + count);
- if (offset + count < 0 || offset + count > ascii.length)
+ // equivalent to: offset + count < 0 || offset + count > ascii.length
+ if (ascii.length - offset < count)
throw new StringIndexOutOfBoundsException("offset + count: "
+ (offset + count));
value = new char[count];
@@ -338,7 +339,8 @@ public final class String implements Serializable, Comparable, CharSequence
throw new StringIndexOutOfBoundsException("offset: " + offset);
if (count < 0)
throw new StringIndexOutOfBoundsException("count: " + count);
- if (offset + count < 0 || offset + count > data.length)
+ // equivalent to: offset + count < 0 || offset + count > data.length
+ if (data.length - offset < count)
throw new StringIndexOutOfBoundsException("offset + count: "
+ (offset + count));
try
@@ -418,7 +420,8 @@ public final class String implements Serializable, Comparable, CharSequence
throw new StringIndexOutOfBoundsException("offset: " + offset);
if (count < 0)
throw new StringIndexOutOfBoundsException("count: " + count);
- if (offset + count < 0 || offset + count > data.length)
+ // equivalent to: offset + count < 0 || offset + count > data.length
+ if (data.length - offset < count)
throw new StringIndexOutOfBoundsException("offset + count: "
+ (offset + count));
int o, c;
@@ -533,7 +536,8 @@ public final class String implements Serializable, Comparable, CharSequence
throw new StringIndexOutOfBoundsException("offset: " + offset);
if (count < 0)
throw new StringIndexOutOfBoundsException("count: " + count);
- if (offset + count < 0 || offset + count > data.length)
+ // equivalent to: offset + count < 0 || offset + count > data.length
+ if (data.length - offset < count)
throw new StringIndexOutOfBoundsException("offset + count: "
+ (offset + count));
if (dont_copy)
@@ -1761,7 +1765,7 @@ public final class String implements Serializable, Comparable, CharSequence
/**
* Return the number of code points between two indices in the
- * StringBuffer. An unpaired surrogate counts as a
+ * String. An unpaired surrogate counts as a
* code point for this purpose. Characters outside the indicated
* range are not examined, even if the range ends in the middle of a
* surrogate pair.
@@ -1879,6 +1883,8 @@ public final class String implements Serializable, Comparable, CharSequence
* described in s.
* @param s the CharSequence
* @return true iff this String contains s
+ *
+ * @since 1.5
*/
public boolean contains (CharSequence s)
{
diff --git a/libjava/classpath/java/lang/Thread.java b/libjava/classpath/java/lang/Thread.java
index 763228c16ef..9afde5bfd03 100644
--- a/libjava/classpath/java/lang/Thread.java
+++ b/libjava/classpath/java/lang/Thread.java
@@ -38,9 +38,9 @@ exception statement from your version. */
package java.lang;
+import gnu.java.util.WeakIdentityHashMap;
import java.security.Permission;
import java.util.Map;
-import java.util.WeakHashMap;
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
* "The Java Language Specification", ISBN 0-201-63451-1
@@ -137,7 +137,7 @@ public class Thread implements Runnable
/** Thread local storage. Package accessible for use by
* InheritableThreadLocal.
*/
- WeakHashMap locals;
+ WeakIdentityHashMap locals;
/**
* Allocates a new Thread object. This constructor has
@@ -996,7 +996,7 @@ public class Thread implements Runnable
Map locals = thread.locals;
if (locals == null)
{
- locals = thread.locals = new WeakHashMap();
+ locals = thread.locals = new WeakIdentityHashMap();
}
return locals;
}
diff --git a/libjava/classpath/java/lang/ThreadLocal.java b/libjava/classpath/java/lang/ThreadLocal.java
index bc839044574..aceb2557a54 100644
--- a/libjava/classpath/java/lang/ThreadLocal.java
+++ b/libjava/classpath/java/lang/ThreadLocal.java
@@ -1,5 +1,5 @@
/* ThreadLocal -- a variable with a unique value per thread
- Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2002, 2003, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -95,21 +95,6 @@ public class ThreadLocal
*/
static final Object NULL = new Object();
- /**
- * Serves as a key for the Thread.locals WeakHashMap.
- * We can't use "this", because a subclass may override equals/hashCode
- * and we need to use object identity for the map.
- */
- final Key key = new Key();
-
- class Key
- {
- ThreadLocal get()
- {
- return ThreadLocal.this;
- }
- }
-
/**
* Creates a ThreadLocal object without associating any value to it yet.
*/
@@ -143,11 +128,11 @@ public class ThreadLocal
Map map = Thread.getThreadLocals();
// Note that we don't have to synchronize, as only this thread will
// ever modify the map.
- Object value = map.get(key);
+ Object value = map.get(this);
if (value == null)
{
value = initialValue();
- map.put(key, value == null ? NULL : value);
+ map.put(this, value == null ? NULL : value);
}
return value == NULL ? null : value;
}
@@ -165,6 +150,6 @@ public class ThreadLocal
Map map = Thread.getThreadLocals();
// Note that we don't have to synchronize, as only this thread will
// ever modify the map.
- map.put(key, value == null ? NULL : value);
+ map.put(this, value == null ? NULL : value);
}
}
diff --git a/libjava/classpath/java/net/DatagramSocket.java b/libjava/classpath/java/net/DatagramSocket.java
index 40bafbb34dd..d8837c006b5 100644
--- a/libjava/classpath/java/net/DatagramSocket.java
+++ b/libjava/classpath/java/net/DatagramSocket.java
@@ -176,7 +176,12 @@ public class DatagramSocket
{
String propVal = SystemProperties.getProperty("impl.prefix");
if (propVal == null || propVal.equals(""))
- impl = new PlainDatagramSocketImpl();
+ {
+ if (factory != null)
+ impl = factory.createDatagramSocketImpl();
+ else
+ impl = new PlainDatagramSocketImpl();
+ }
else
try
{
diff --git a/libjava/classpath/java/net/InetAddress.java b/libjava/classpath/java/net/InetAddress.java
index 94dc6cb6d84..7277331bb26 100644
--- a/libjava/classpath/java/net/InetAddress.java
+++ b/libjava/classpath/java/net/InetAddress.java
@@ -43,7 +43,6 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
-import java.util.HashMap;
import java.util.StringTokenizer;
/**
@@ -65,22 +64,6 @@ public class InetAddress implements Serializable
{
private static final long serialVersionUID = 3286316764910316507L;
- /**
- * The default DNS hash table size,
- * Use a prime number happy with hash table.
- */
- private static final int DEFAULT_CACHE_SIZE = 89;
-
- /**
- * The default caching period in minutes.
- */
- private static final int DEFAULT_CACHE_PERIOD = 4 * 60;
-
- /**
- * Percentage of cache entries to purge when the table gets full.
- */
- private static final int DEFAULT_CACHE_PURGE_PCT = 30;
-
/**
* The special IP address INADDR_ANY.
*/
@@ -96,50 +79,8 @@ public class InetAddress implements Serializable
*/
static InetAddress LOCALHOST;
- /**
- * The size of the cache.
- */
- private static int cache_size = 0;
-
- /**
- * The length of time we will continue to read the address from cache
- * before forcing another lookup.
- */
- private static int cache_period = 0;
-
- /**
- * What percentage of the cache we will purge if it gets full.
- */
- private static int cache_purge_pct = 0;
-
- /**
- * HashMap to use as DNS lookup cache.
- * Use HashMap because all accesses to cache are already synchronized.
- */
- private static HashMap cache;
-
static
{
- // Look for properties that override default caching behavior
- cache_size =
- Integer.getInteger("gnu.java.net.dns_cache_size", DEFAULT_CACHE_SIZE)
- .intValue();
- cache_period =
- Integer.getInteger("gnu.java.net.dns_cache_period",
- DEFAULT_CACHE_PERIOD * 60 * 1000).intValue();
-
- cache_purge_pct =
- Integer.getInteger("gnu.java.net.dns_cache_purge_pct",
- DEFAULT_CACHE_PURGE_PCT).intValue();
-
- // Fallback to defaults if necessary
- if ((cache_purge_pct < 1) || (cache_purge_pct > 100))
- cache_purge_pct = DEFAULT_CACHE_PURGE_PCT;
-
- // Create the cache
- if (cache_size != 0)
- cache = new HashMap(cache_size);
-
// precompute the ANY_IF address
try
{
@@ -173,11 +114,6 @@ public class InetAddress implements Serializable
*/
String hostName;
- /**
- * The time this address was looked up.
- */
- transient long lookup_time;
-
/**
* The field 'family' seems to be the AF_ value.
* FIXME: Much of the code in the other java.net classes does not make
@@ -200,8 +136,6 @@ public class InetAddress implements Serializable
addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone();
hostName = hostname;
- lookup_time = System.currentTimeMillis();
-
family = 2; /* AF_INET */
}
@@ -649,20 +583,17 @@ public class InetAddress implements Serializable
InetAddress[] addresses;
+ if (hostname != null)
+ hostname = hostname.trim();
+
// Default to current host if necessary
- if (hostname == null)
+ if (hostname == null || hostname.equals(""))
{
addresses = new InetAddress[1];
addresses[0] = LOCALHOST;
return addresses;
}
- // Check the cache for this host before doing a lookup
- addresses = checkCacheFor(hostname);
-
- if (addresses != null)
- return addresses;
-
// Not in cache, try the lookup
byte[][] iplist = VMInetAddress.getHostByName(hostname);
@@ -679,70 +610,9 @@ public class InetAddress implements Serializable
addresses[i] = new Inet4Address(iplist[i], hostname);
}
- addToCache(hostname, addresses);
return addresses;
}
- /**
- * This method checks the DNS cache to see if we have looked this hostname
- * up before. If so, we return the cached addresses unless it has been in the
- * cache too long.
- *
- * @param hostname The hostname to check for
- *
- * @return The InetAddress for this hostname or null if not available
- */
- private static synchronized InetAddress[] checkCacheFor(String hostname)
- {
- InetAddress[] addresses = null;
-
- if (cache_size == 0)
- return null;
-
- Object obj = cache.get(hostname);
- if (obj == null)
- return null;
-
- if (obj instanceof InetAddress[])
- addresses = (InetAddress[]) obj;
-
- if (addresses == null)
- return null;
-
- if (cache_period != -1)
- if ((System.currentTimeMillis() - addresses[0].lookup_time) > cache_period)
- {
- cache.remove(hostname);
- return null;
- }
-
- return addresses;
- }
-
- /**
- * This method adds an InetAddress object to our DNS cache. Note that
- * if the cache is full, then we run a purge to get rid of old entries.
- * This will cause a performance hit, thus applications using lots of
- * lookups should set the cache size to be very large.
- *
- * @param hostname The hostname to cache this address under
- * @param obj The InetAddress or InetAddress array to store
- */
- private static synchronized void addToCache(String hostname, Object obj)
- {
- if (cache_size == 0)
- return;
-
- // Check to see if hash table is full
- if (cache_size != -1)
- if (cache.size() == cache_size)
- {
- // FIXME Add code to purge later.
- }
-
- cache.put(hostname, obj);
- }
-
/**
* Returns the special address INADDR_ANY used for binding to a local
* port on all IP addresses hosted by a the local host.
@@ -757,6 +627,7 @@ public class InetAddress implements Serializable
{
byte[] tmp = VMInetAddress.lookupInaddrAny();
inaddr_any = new Inet4Address(tmp, null);
+ inaddr_any.hostName = inaddr_any.getHostName();
}
return inaddr_any;
diff --git a/libjava/classpath/java/net/URL.java b/libjava/classpath/java/net/URL.java
index 1d947a0b46a..168c67a19ee 100644
--- a/libjava/classpath/java/net/URL.java
+++ b/libjava/classpath/java/net/URL.java
@@ -1,5 +1,5 @@
/* URL.java -- Uniform Resource Locator Class
- Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,6 +38,7 @@ exception statement from your version. */
package java.net;
+import gnu.classpath.SystemProperties;
import gnu.java.net.URLParseError;
import java.io.IOException;
@@ -198,7 +199,7 @@ public final class URL implements Serializable
static
{
- String s = System.getProperty("gnu.java.net.nocache_protocol_handlers");
+ String s = SystemProperties.getProperty("gnu.java.net.nocache_protocol_handlers");
if (s == null)
cache_handlers = true;
@@ -342,7 +343,7 @@ public final class URL implements Serializable
*/
public URL(URL context, String spec) throws MalformedURLException
{
- this(context, spec, (URLStreamHandler) null);
+ this(context, spec, (context == null) ? (URLStreamHandler)null : context.ph);
}
/**
@@ -867,7 +868,7 @@ public final class URL implements Serializable
// Except in very unusual environments the JDK specified one shouldn't
// ever be needed (or available).
String ph_search_path =
- System.getProperty("java.protocol.handler.pkgs");
+ SystemProperties.getProperty("java.protocol.handler.pkgs");
// Tack our default package on at the ends.
if (ph_search_path != null)
diff --git a/libjava/classpath/java/nio/charset/Charset.java b/libjava/classpath/java/nio/charset/Charset.java
index 91801ddac87..3637703a32c 100644
--- a/libjava/classpath/java/nio/charset/Charset.java
+++ b/libjava/classpath/java/nio/charset/Charset.java
@@ -121,6 +121,8 @@ public abstract class Charset implements Comparable
*
* This may be set by the user or VM with the file.encoding
* property.
+ *
+ * @since 1.5
*/
public static Charset defaultCharset()
{
diff --git a/libjava/classpath/java/nio/charset/spi/CharsetProvider.java b/libjava/classpath/java/nio/charset/spi/CharsetProvider.java
index f0d40ab8591..496ccf92789 100644
--- a/libjava/classpath/java/nio/charset/spi/CharsetProvider.java
+++ b/libjava/classpath/java/nio/charset/spi/CharsetProvider.java
@@ -1,5 +1,5 @@
/* CharsetProvider.java -- charset service provider interface
- Copyright (C) 2002 Free Software Foundation
+ Copyright (C) 2002, 2006 Free Software Foundation
This file is part of GNU Classpath.
@@ -67,8 +67,12 @@ public abstract class CharsetProvider
*/
protected CharsetProvider()
{
+ // We only do the security check for custom providers, not for the
+ // built in ones.
SecurityManager s = System.getSecurityManager();
- if (s != null)
+ if (s != null &&
+ ! (this instanceof gnu.java.nio.charset.Provider
+ || this instanceof gnu.java.nio.charset.iconv.IconvProvider))
s.checkPermission(new RuntimePermission("charsetProvider"));
}
diff --git a/libjava/classpath/java/security/MessageDigest.java b/libjava/classpath/java/security/MessageDigest.java
index 8684f2083b1..8a6af645be1 100644
--- a/libjava/classpath/java/security/MessageDigest.java
+++ b/libjava/classpath/java/security/MessageDigest.java
@@ -1,5 +1,5 @@
/* MessageDigest.java --- The message digest interface.
- Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002, 2003, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -167,6 +167,9 @@ public abstract class MessageDigest extends MessageDigestSpi
public static MessageDigest getInstance(String algorithm, String provider)
throws NoSuchAlgorithmException, NoSuchProviderException
{
+ if (provider != null)
+ provider = provider.trim();
+
if (provider == null || provider.length() == 0)
throw new IllegalArgumentException("Illegal provider");
diff --git a/libjava/classpath/java/security/Security.java b/libjava/classpath/java/security/Security.java
index fd51d0535b3..d26d049c524 100644
--- a/libjava/classpath/java/security/Security.java
+++ b/libjava/classpath/java/security/Security.java
@@ -1,5 +1,6 @@
/* Security.java --- Java base security class implementation
- Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -41,6 +42,7 @@ package java.security;
import gnu.classpath.SystemProperties;
import gnu.classpath.Configuration;
+import gnu.classpath.VMStackWalker;
import java.io.IOException;
import java.io.InputStream;
@@ -354,6 +356,14 @@ public final class Security
*/
public static Provider getProvider(String name)
{
+ if (name == null)
+ return null;
+ else
+ {
+ name = name.trim();
+ if (name.length() == 0)
+ return null;
+ }
Provider p;
int max = providers.size ();
for (int i = 0; i < max; i++)
@@ -383,8 +393,11 @@ public final class Security
*/
public static String getProperty(String key)
{
+ // XXX To prevent infinite recursion when the SecurityManager calls us,
+ // don't do a security check if the caller is trusted (by virtue of having
+ // been loaded by the bootstrap class loader).
SecurityManager sm = System.getSecurityManager();
- if (sm != null)
+ if (sm != null && VMStackWalker.getCallingClassLoader() != null)
sm.checkSecurityAccess("getProperty." + key);
return secprops.getProperty(key);
@@ -399,20 +412,23 @@ public final class Security
*
*
* @param key the name of the property to be set.
- * @param datnum the value of the property to be set.
+ * @param datum the value of the property to be set.
* @throws SecurityException if a security manager exists and its
* {@link SecurityManager#checkPermission(Permission)} method denies access
* to set the specified security property value.
* @see #getProperty(String)
* @see SecurityPermission
*/
- public static void setProperty(String key, String datnum)
+ public static void setProperty(String key, String datum)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkSecurityAccess("setProperty." + key);
- secprops.put(key, datnum);
+ if (datum == null)
+ secprops.remove(key);
+ else
+ secprops.put(key, datum);
}
/**
diff --git a/libjava/classpath/java/text/Bidi.java b/libjava/classpath/java/text/Bidi.java
new file mode 100644
index 00000000000..57b9a88dfa7
--- /dev/null
+++ b/libjava/classpath/java/text/Bidi.java
@@ -0,0 +1,78 @@
+/* Bidi.java -- Bidirectional Algorithm implementation
+ Copyright (C) 2005 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;
+
+/**
+ * Bidirectional Algorithm implementation.
+ *
+ * TODO/FIXME Only one method requiresBidi is implemented
+ * for now by using Character. The full algorithm is Unicode Standard
+ * Annex #9: The Bidirectional Algorithm. A full implementation is
+ * GNU FriBidi.
+ */
+public class Bidi
+{
+ /**
+ * Returns false if all characters in the text between start and end
+ * are all left-to-right text. This implementation is just calls
+ * Character.getDirectionality(char) on all characters
+ * and makes sure all characters are either explicitly left-to-right
+ * or neutral in directionality (character types L, EN, ES, ET, AN,
+ * CS, S and WS).
+ */
+ public static boolean requiresBidi(char[] text, int start, int end)
+ {
+ for (int i = start; i < end; i++)
+ {
+ byte dir = Character.getDirectionality(text[i]);
+ if (dir != Character.DIRECTIONALITY_LEFT_TO_RIGHT
+ && dir != Character.DIRECTIONALITY_EUROPEAN_NUMBER
+ && dir != Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR
+ && dir != Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR
+ && dir != Character.DIRECTIONALITY_ARABIC_NUMBER
+ && dir != Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR
+ && dir != Character.DIRECTIONALITY_SEGMENT_SEPARATOR
+ && dir != Character.DIRECTIONALITY_WHITESPACE)
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/libjava/classpath/java/text/DecimalFormat.java b/libjava/classpath/java/text/DecimalFormat.java
index 6dadb0ce333..a9ec7767f94 100644
--- a/libjava/classpath/java/text/DecimalFormat.java
+++ b/libjava/classpath/java/text/DecimalFormat.java
@@ -182,7 +182,9 @@ public class DecimalFormat extends NumberFormat
{
groupingUsed = saw_group;
groupingSize = (byte) countSinceGroup;
- minimumIntegerDigits = zeroCount;
+ // Checking "zeroCount > 0" avoids 0 being formatted into "" with "#".
+ if (zeroCount > 0)
+ minimumIntegerDigits = zeroCount;
}
// Early termination.
diff --git a/libjava/classpath/java/util/AbstractMap.java b/libjava/classpath/java/util/AbstractMap.java
index 7cd6436a308..b4ab882addf 100644
--- a/libjava/classpath/java/util/AbstractMap.java
+++ b/libjava/classpath/java/util/AbstractMap.java
@@ -594,13 +594,13 @@ public abstract class AbstractMap implements Map
*
* @param o1 the first object
* @param o2 the second object
- * @return o1 == null ? o2 == null : o1.equals(o2)
+ * @return o1 == o2 || (o1 != null && o1.equals(o2))
*/
// Package visible for use throughout java.util.
// It may be inlined since it is final.
static final boolean equals(Object o1, Object o2)
{
- return o1 == null ? o2 == null : o1.equals(o2);
+ return o1 == o2 || (o1 != null && o1.equals(o2));
}
/**
diff --git a/libjava/classpath/java/util/ArrayList.java b/libjava/classpath/java/util/ArrayList.java
index 752f9da4ee0..50b5638ede0 100644
--- a/libjava/classpath/java/util/ArrayList.java
+++ b/libjava/classpath/java/util/ArrayList.java
@@ -92,7 +92,7 @@ public class ArrayList extends AbstractList
/**
* The default capacity for new ArrayLists.
*/
- private static final int DEFAULT_CAPACITY = 16;
+ private static final int DEFAULT_CAPACITY = 10;
/**
* The number of elements in this list.
diff --git a/libjava/classpath/java/util/Collections.java b/libjava/classpath/java/util/Collections.java
index e650bf8bda9..dc37bad8a93 100644
--- a/libjava/classpath/java/util/Collections.java
+++ b/libjava/classpath/java/util/Collections.java
@@ -670,10 +670,10 @@ public class Collections
for ( ; i != pos; i--, o = itr.previous());
forward = false;
}
- final int d = compare(key, o, c);
+ final int d = compare(o, key, c);
if (d == 0)
return pos;
- else if (d < 0)
+ else if (d > 0)
hi = pos - 1;
else
// This gets the insertion point right on the last loop
@@ -685,10 +685,10 @@ public class Collections
while (low <= hi)
{
pos = (low + hi) >> 1;
- final int d = compare(key, l.get(pos), c);
+ final int d = compare(l.get(pos), key, c);
if (d == 0)
return pos;
- else if (d < 0)
+ else if (d > 0)
hi = pos - 1;
else
// This gets the insertion point right on the last loop
diff --git a/libjava/classpath/java/util/Hashtable.java b/libjava/classpath/java/util/Hashtable.java
index 011cafaa855..76b0d5c15bd 100644
--- a/libjava/classpath/java/util/Hashtable.java
+++ b/libjava/classpath/java/util/Hashtable.java
@@ -1,6 +1,7 @@
/* Hashtable.java -- a class providing a basic hashtable 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.
@@ -110,12 +111,6 @@ public class Hashtable extends Dictionary
*/
private static final int DEFAULT_CAPACITY = 11;
- /** An "enum" of iterator types. */
- // Package visible for use by nested classes.
- static final int KEYS = 0,
- VALUES = 1,
- ENTRIES = 2;
-
/**
* The default load factor; this is explicitly specified by the spec.
*/
@@ -302,7 +297,7 @@ public class Hashtable extends Dictionary
*/
public Enumeration keys()
{
- return new Enumerator(KEYS);
+ return new KeyEnumerator();
}
/**
@@ -316,7 +311,7 @@ public class Hashtable extends Dictionary
*/
public Enumeration elements()
{
- return new Enumerator(VALUES);
+ return new ValueEnumerator();
}
/**
@@ -333,20 +328,19 @@ public class Hashtable extends Dictionary
*/
public synchronized boolean contains(Object value)
{
+ if (value == null)
+ throw new NullPointerException();
+
for (int i = buckets.length - 1; i >= 0; i--)
{
HashEntry e = buckets[i];
while (e != null)
{
- if (value.equals(e.value))
+ if (e.value.equals(value))
return true;
e = e.next;
}
}
-
- // Must throw on null argument even if the table is empty
- if (value == null)
- throw new NullPointerException();
return false;
}
@@ -385,7 +379,7 @@ public class Hashtable extends Dictionary
HashEntry e = buckets[idx];
while (e != null)
{
- if (key.equals(e.key))
+ if (e.key.equals(key))
return true;
e = e.next;
}
@@ -408,7 +402,7 @@ public class Hashtable extends Dictionary
HashEntry e = buckets[idx];
while (e != null)
{
- if (key.equals(e.key))
+ if (e.key.equals(key))
return e.value;
e = e.next;
}
@@ -438,7 +432,7 @@ public class Hashtable extends Dictionary
while (e != null)
{
- if (key.equals(e.key))
+ if (e.key.equals(key))
{
// Bypass e.setValue, since we already know value is non-null.
Object r = e.value;
@@ -484,7 +478,7 @@ public class Hashtable extends Dictionary
while (e != null)
{
- if (key.equals(e.key))
+ if (e.key.equals(key))
{
modCount++;
if (last == null)
@@ -581,8 +575,8 @@ public class Hashtable extends Dictionary
{
// Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the
- // unsynchronized HashIterator instead.
- Iterator entries = new HashIterator(ENTRIES);
+ // unsynchronized EntryIterator instead.
+ Iterator entries = new EntryIterator();
StringBuffer r = new StringBuffer("{");
for (int pos = size; pos > 0; pos--)
{
@@ -624,7 +618,7 @@ public class Hashtable extends Dictionary
public Iterator iterator()
{
- return new HashIterator(KEYS);
+ return new KeyIterator();
}
public void clear()
@@ -682,7 +676,7 @@ public class Hashtable extends Dictionary
public Iterator iterator()
{
- return new HashIterator(VALUES);
+ return new ValueIterator();
}
public void clear()
@@ -734,7 +728,7 @@ public class Hashtable extends Dictionary
public Iterator iterator()
{
- return new HashIterator(ENTRIES);
+ return new EntryIterator();
}
public void clear()
@@ -798,8 +792,8 @@ public class Hashtable extends Dictionary
{
// Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the
- // unsynchronized HashIterator instead.
- Iterator itr = new HashIterator(ENTRIES);
+ // unsynchronized EntryIterator instead.
+ Iterator itr = new EntryIterator();
int hashcode = 0;
for (int pos = size; pos > 0; pos--)
hashcode += itr.next().hashCode();
@@ -844,7 +838,7 @@ public class Hashtable extends Dictionary
HashEntry e = buckets[idx];
while (e != null)
{
- if (o.equals(e))
+ if (e.equals(o))
return e;
e = e.next;
}
@@ -904,8 +898,12 @@ public class Hashtable extends Dictionary
if (dest != null)
{
- while (dest.next != null)
- dest = dest.next;
+ HashEntry next = dest.next;
+ while (next != null)
+ {
+ dest = next;
+ next = dest.next;
+ }
dest.next = e;
}
else
@@ -940,8 +938,8 @@ public class Hashtable extends Dictionary
s.writeInt(size);
// Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the
- // unsynchronized HashIterator instead.
- Iterator it = new HashIterator(ENTRIES);
+ // unsynchronized EntryIterator instead.
+ Iterator it = new EntryIterator();
while (it.hasNext())
{
HashEntry entry = (HashEntry) it.next();
@@ -980,21 +978,17 @@ public class Hashtable extends Dictionary
/**
* A class which implements the Iterator interface and is used for
* iterating over Hashtables.
- * This implementation is parameterized to give a sequential view of
- * keys, values, or entries; it also allows the removal of elements,
- * as per the Javasoft spec. Note that it is not synchronized; this is
- * a performance enhancer since it is never exposed externally and is
- * only used within synchronized blocks above.
+ * This implementation iterates entries. Subclasses are used to
+ * iterate key and values. It also allows the removal of elements,
+ * as per the Javasoft spec. Note that it is not synchronized; this
+ * is a performance enhancer since it is never exposed externally
+ * and is only used within synchronized blocks above.
*
* @author Jon Zeppieri
+ * @author Fridjof Siebert
*/
- private final class HashIterator implements Iterator
+ private class EntryIterator implements Iterator
{
- /**
- * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
- * or {@link #ENTRIES}.
- */
- final int type;
/**
* The number of modifications to the backing Hashtable that we know about.
*/
@@ -1013,14 +1007,13 @@ public class Hashtable extends Dictionary
HashEntry next;
/**
- * Construct a new HashIterator with the supplied type.
- * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
+ * Construct a new EtryIterator
*/
- HashIterator(int type)
+ EntryIterator()
{
- this.type = type;
}
+
/**
* Returns true if the Iterator has more elements.
* @return true if there are more elements
@@ -1049,14 +1042,13 @@ public class Hashtable extends Dictionary
HashEntry e = next;
while (e == null)
- e = buckets[--idx];
+ if (idx <= 0)
+ return null;
+ else
+ e = buckets[--idx];
next = e.next;
last = e;
- if (type == VALUES)
- return e.value;
- if (type == KEYS)
- return e.key;
return e;
}
@@ -1077,29 +1069,70 @@ public class Hashtable extends Dictionary
last = null;
knownMod++;
}
- } // class HashIterator
+ } // class EntryIterator
+
+ /**
+ * A class which implements the Iterator interface and is used for
+ * iterating over keys in Hashtables.
+ *
+ * @author Fridtjof Siebert
+ */
+ private class KeyIterator extends EntryIterator
+ {
+ /**
+ * Returns the next element in the Iterator's sequential view.
+ *
+ * @return the next element
+ *
+ * @throws ConcurrentModificationException if the hashtable was modified
+ * @throws NoSuchElementException if there is none
+ */
+ public Object next()
+ {
+ return ((HashEntry)super.next()).key;
+ }
+ } // class KeyIterator
+
/**
- * Enumeration view of this Hashtable, providing sequential access to its
- * elements; this implementation is parameterized to provide access either
- * to the keys or to the values in the Hashtable.
+ * A class which implements the Iterator interface and is used for
+ * iterating over values in Hashtables.
+ *
+ * @author Fridtjof Siebert
+ */
+ private class ValueIterator extends EntryIterator
+ {
+ /**
+ * Returns the next element in the Iterator's sequential view.
+ *
+ * @return the next element
+ *
+ * @throws ConcurrentModificationException if the hashtable was modified
+ * @throws NoSuchElementException if there is none
+ */
+ public Object next()
+ {
+ return ((HashEntry)super.next()).value;
+ }
+ } // class ValueIterator
+
+ /**
+ * Enumeration view of the entries in this Hashtable, providing
+ * sequential access to its elements.
*
* NOTE: Enumeration is not safe if new elements are put in the table
* as this could cause a rehash and we'd completely lose our place. Even
* without a rehash, it is undetermined if a new element added would
* appear in the enumeration. The spec says nothing about this, but
- * the "Java Class Libraries" book infers that modifications to the
+ * the "Java Class Libraries" book implies that modifications to the
* hashtable during enumeration causes indeterminate results. Don't do it!
*
* @author Jon Zeppieri
+ * @author Fridjof Siebert
*/
- private final class Enumerator implements Enumeration
+ private class EntryEnumerator implements Enumeration
{
- /**
- * The type of this Iterator: {@link #KEYS} or {@link #VALUES}.
- */
- final int type;
/** The number of elements remaining to be returned by next(). */
int count = size;
/** Current index in the physical hash table. */
@@ -1113,11 +1146,10 @@ public class Hashtable extends Dictionary
/**
* Construct the enumeration.
- * @param type either {@link #KEYS} or {@link #VALUES}.
*/
- Enumerator(int type)
+ EntryEnumerator()
{
- this.type = type;
+ // Nothing to do here.
}
/**
@@ -1142,10 +1174,78 @@ public class Hashtable extends Dictionary
HashEntry e = next;
while (e == null)
- e = buckets[--idx];
+ if (idx <= 0)
+ return null;
+ else
+ e = buckets[--idx];
next = e.next;
- return type == VALUES ? e.value : e.key;
+ return e;
+ }
+ } // class EntryEnumerator
+
+
+ /**
+ * Enumeration view of this Hashtable, providing sequential access to its
+ * elements.
+ *
+ * NOTE: Enumeration is not safe if new elements are put in the table
+ * as this could cause a rehash and we'd completely lose our place. Even
+ * without a rehash, it is undetermined if a new element added would
+ * appear in the enumeration. The spec says nothing about this, but
+ * the "Java Class Libraries" book implies that modifications to the
+ * hashtable during enumeration causes indeterminate results. Don't do it!
+ *
+ * @author Jon Zeppieri
+ * @author Fridjof Siebert
+ */
+ private final class KeyEnumerator extends EntryEnumerator
+ {
+ /**
+ * Returns the next element.
+ * @return the next element
+ * @throws NoSuchElementException if there is none.
+ */
+ public Object nextElement()
+ {
+ HashEntry entry = (HashEntry) super.nextElement();
+ Object retVal = null;
+ if (entry != null)
+ retVal = entry.key;
+ return retVal;
}
- } // class Enumerator
+ } // class KeyEnumerator
+
+
+ /**
+ * Enumeration view of this Hashtable, providing sequential access to its
+ * values.
+ *
+ * NOTE: Enumeration is not safe if new elements are put in the table
+ * as this could cause a rehash and we'd completely lose our place. Even
+ * without a rehash, it is undetermined if a new element added would
+ * appear in the enumeration. The spec says nothing about this, but
+ * the "Java Class Libraries" book implies that modifications to the
+ * hashtable during enumeration causes indeterminate results. Don't do it!
+ *
+ * @author Jon Zeppieri
+ * @author Fridjof Siebert
+ */
+ private final class ValueEnumerator extends EntryEnumerator
+ {
+ /**
+ * Returns the next element.
+ * @return the next element
+ * @throws NoSuchElementException if there is none.
+ */
+ public Object nextElement()
+ {
+ HashEntry entry = (HashEntry) super.nextElement();
+ Object retVal = null;
+ if (entry != null)
+ retVal = entry.value;
+ return retVal;
+ }
+ } // class ValueEnumerator
+
} // class Hashtable
diff --git a/libjava/classpath/java/util/Properties.java b/libjava/classpath/java/util/Properties.java
index 7c468da8b4f..eb208f5a93d 100644
--- a/libjava/classpath/java/util/Properties.java
+++ b/libjava/classpath/java/util/Properties.java
@@ -47,15 +47,10 @@ import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.DefaultHandler2;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
@@ -743,173 +738,64 @@ label = Name:\\u0020
throw new NullPointerException("Null input stream supplied.");
try
{
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setValidating(false); /* Don't use the URI */
- XMLReader parser = factory.newSAXParser().getXMLReader();
- PropertiesHandler handler = new PropertiesHandler();
- parser.setContentHandler(handler);
- parser.setProperty("http://xml.org/sax/properties/lexical-handler",
- handler);
- parser.parse(new InputSource(in));
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ // Don't resolve external entity references
+ factory.setProperty("javax.xml.stream.isSupportingExternalEntities",
+ Boolean.FALSE);
+ XMLStreamReader reader = factory.createXMLStreamReader(in);
+ String name, key = null;
+ StringBuffer buf = null;
+ while (reader.hasNext())
+ {
+ switch (reader.next())
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ name = reader.getLocalName();
+ if (buf == null && "entry".equals(name))
+ {
+ key = reader.getAttributeValue(null, "key");
+ if (key == null)
+ {
+ String msg = "missing 'key' attribute";
+ throw new InvalidPropertiesFormatException(msg);
+ }
+ buf = new StringBuffer();
+ }
+ else if (!"properties".equals(name) && !"comment".equals(name))
+ {
+ String msg = "unexpected element name '" + name + "'";
+ throw new InvalidPropertiesFormatException(msg);
+ }
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ name = reader.getLocalName();
+ if (buf != null && "entry".equals(name))
+ {
+ put(key, buf.toString());
+ buf = null;
+ }
+ else if (!"properties".equals(name) && !"comment".equals(name))
+ {
+ String msg = "unexpected element name '" + name + "'";
+ throw new InvalidPropertiesFormatException(msg);
+ }
+ break;
+ case XMLStreamConstants.CHARACTERS:
+ case XMLStreamConstants.SPACE:
+ case XMLStreamConstants.CDATA:
+ if (buf != null)
+ buf.append(reader.getText());
+ break;
+ }
+ }
+ reader.close();
}
- catch (SAXException e)
+ catch (XMLStreamException e)
{
throw (InvalidPropertiesFormatException)
new InvalidPropertiesFormatException("Error in parsing XML.").
initCause(e);
}
- catch (ParserConfigurationException e)
- {
- throw (IOException)
- new IOException("An XML parser could not be found.").
- initCause(e);
- }
}
- /**
- * This class deals with the parsing of XML using
- *
- * http://java.sun.com/dtd/properties.dtd.
- *
- * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
- * @since 1.5
- */
- private class PropertiesHandler
- extends DefaultHandler2
- {
-
- /**
- * The current key.
- */
- private String key;
-
- /**
- * The current value.
- */
- private String value;
-
- /**
- * A flag to check whether a valid DTD declaration has been seen.
- */
- private boolean dtdDeclSeen;
-
- /**
- * Constructs a new Properties handler.
- */
- public PropertiesHandler()
- {
- key = null;
- value = null;
- dtdDeclSeen = false;
- }
-
- /**
- * - * Captures the start of the DTD declarations, if they exist. - * A valid properties file must declare the following doctype: - *
- *
- * !DOCTYPE properties SYSTEM
- * "http://java.sun.com/dtd/properties.dtd"
- *