diff options
author | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-06-27 20:01:40 +0000 |
---|---|---|
committer | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-06-27 20:01:40 +0000 |
commit | 3b00aa20227be4b0f2314278dcea3ef3739c44aa (patch) | |
tree | f7d11ad3bf3342c619595f748dbb91b184b8324c /java | |
parent | 78c2fbfb5f722402791ad87028a3a5f62ed4c086 (diff) | |
download | classpath-3b00aa20227be4b0f2314278dcea3ef3739c44aa.tar.gz |
2006-06-27 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge of HEAD --> generics-branch for 2006/06/16
to 2006/06/27.
Diffstat (limited to 'java')
31 files changed, 2295 insertions, 609 deletions
diff --git a/java/awt/Component.java b/java/awt/Component.java index 26df1554f..0a987ee3b 100644 --- a/java/awt/Component.java +++ b/java/awt/Component.java @@ -70,6 +70,7 @@ import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; import java.awt.peer.ComponentPeer; import java.awt.peer.LightweightPeer; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; @@ -427,6 +428,24 @@ public abstract class Component Dimension minSize; /** + * Flag indicating whether the minimum size for the component has been set + * by a call to {@link #setMinimumSize(Dimension)} with a non-null value. + */ + boolean minSizeSet; + + /** + * The maximum size for the component. + * @see #setMaximumSize(Dimension) + */ + Dimension maxSize; + + /** + * A flag indicating whether the maximum size for the component has been set + * by a call to {@link #setMaximumSize(Dimension)} with a non-null value. + */ + boolean maxSizeSet; + + /** * Cached information on the preferred size. Should have been transient. * * @serial ignore @@ -434,6 +453,12 @@ public abstract class Component Dimension prefSize; /** + * Flag indicating whether the preferred size for the component has been set + * by a call to {@link #setPreferredSize(Dimension)} with a non-null value. + */ + boolean prefSizeSet; + + /** * Set to true if an event is to be handled by this component, false if * it is to be passed up the hierarcy. * @@ -607,16 +632,19 @@ public abstract class Component } /** - * Sets the name of this component to the specified name. + * Sets the name of this component to the specified name (this is a bound + * property with the name 'name'). * - * @param name the new name of this component + * @param name the new name (<code>null</code> permitted). * @see #getName() * @since 1.1 */ public void setName(String name) { nameExplicitlySet = true; + String old = this.name; this.name = name; + firePropertyChange("name", old, name); } /** @@ -1584,6 +1612,7 @@ public abstract class Component * * @return the component's preferred size * @see #getMinimumSize() + * @see #setPreferredSize(Dimension) * @see LayoutManager */ public Dimension getPreferredSize() @@ -1592,6 +1621,40 @@ public abstract class Component } /** + * Sets the preferred size that will be returned by + * {@link #getPreferredSize()} always, and sends a + * {@link PropertyChangeEvent} (with the property name 'preferredSize') to + * all registered listeners. + * + * @param size the preferred size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getPreferredSize() + */ + public void setPreferredSize(Dimension size) + { + Dimension old = prefSizeSet ? prefSize : null; + prefSize = size; + prefSizeSet = (size != null); + firePropertyChange("preferredSize", old, size); + } + + /** + * Returns <code>true</code> if the current preferred size is not + * <code>null</code> and was set by a call to + * {@link #setPreferredSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isPreferredSizeSet() + { + return prefSizeSet; + } + + /** * Returns the component's preferred size. * * @return the component's preferred size @@ -1599,7 +1662,7 @@ public abstract class Component */ public Dimension preferredSize() { - if (prefSize == null) + if (!prefSizeSet) { if (peer == null) prefSize = minimumSize(); @@ -1614,6 +1677,7 @@ public abstract class Component * * @return the component's minimum size * @see #getPreferredSize() + * @see #setMinimumSize(Dimension) * @see LayoutManager */ public Dimension getMinimumSize() @@ -1622,6 +1686,39 @@ public abstract class Component } /** + * Sets the minimum size that will be returned by {@link #getMinimumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'minimumSize') to all registered listeners. + * + * @param size the minimum size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getMinimumSize() + */ + public void setMinimumSize(Dimension size) + { + Dimension old = minSizeSet ? minSize : null; + minSize = size; + minSizeSet = (size != null); + firePropertyChange("minimumSize", old, size); + } + + /** + * Returns <code>true</code> if the current minimum size is not + * <code>null</code> and was set by a call to + * {@link #setMinimumSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMinimumSizeSet() + { + return minSizeSet; + } + + /** * Returns the component's minimum size. * * @return the component's minimum size @@ -1640,15 +1737,52 @@ public abstract class Component * * @return the component's maximum size * @see #getMinimumSize() + * @see #setMaximumSize(Dimension) * @see #getPreferredSize() * @see LayoutManager */ public Dimension getMaximumSize() { - return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + if (maxSizeSet) + return maxSize; + else + return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); } /** + * Sets the maximum size that will be returned by {@link #getMaximumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'maximumSize') to all registered listeners. + * + * @param size the maximum size (<code>null</code> permitted). + * + * @since 1.5 + * + * @see #getMaximumSize() + */ + public void setMaximumSize(Dimension size) + { + Dimension old = maxSizeSet ? maxSize : null; + maxSize = size; + maxSizeSet = (size != null); + firePropertyChange("maximumSize", old, size); + } + + /** + * Returns <code>true</code> if the current maximum size is not + * <code>null</code> and was set by a call to + * {@link #setMaximumSize(Dimension)}, otherwise returns <code>false</code>. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMaximumSizeSet() + { + return maxSizeSet; + } + + /** * Returns the preferred horizontal alignment of this component. The value * returned will be between {@link #LEFT_ALIGNMENT} and * {@link #RIGHT_ALIGNMENT}, inclusive. diff --git a/java/awt/Container.java b/java/awt/Container.java index f145d5696..3f3abc5c7 100644 --- a/java/awt/Container.java +++ b/java/awt/Container.java @@ -1688,7 +1688,7 @@ public class Container extends Component int index = -1; if (component != null) { - for (int i = 0; i < component.length; i++) + for (int i = 0; i < ncomponents; i++) { if (component[i] == comp) { diff --git a/java/awt/GridBagConstraints.java b/java/awt/GridBagConstraints.java index 8d8b4fae5..a6a64c3bb 100644 --- a/java/awt/GridBagConstraints.java +++ b/java/awt/GridBagConstraints.java @@ -48,62 +48,99 @@ public class GridBagConstraints implements Cloneable, Serializable { static final long serialVersionUID = -1000070633030801713L; - /** Fill in both directions. */ - public static final int BOTH = 1; - /** Don't fill. */ + // Fill values. + /** + * Don't fill. + */ public static final int NONE = 0; - /** Fill horizontally. */ + + /** + * Fill in both directions. + */ + public static final int BOTH = 1; + + /** + * Fill horizontally. + */ public static final int HORIZONTAL = 2; - /** Fill vertically. */ + + /** + * Fill vertically. + */ public static final int VERTICAL = 3; - /** Position in the center. */ + // Anchor values. + /** + * Position in the center. + */ public static final int CENTER = 10; - /** Position to the east. */ - public static final int EAST = 13; - /** Position to the north. */ + + /** + * Position to the north. + */ public static final int NORTH = 11; - /** Position to the northeast. */ + + /** + * Position to the northeast. + */ public static final int NORTHEAST = 12; - /** Position to the northwest. */ - public static final int NORTHWEST = 18; - /** Position to the south. */ - public static final int SOUTH = 15; - /** Position to the southeast. */ + + /** + * Position to the east. + */ + public static final int EAST = 13; + + /** + * Position to the southeast. + */ public static final int SOUTHEAST = 14; - /** Position to the southwest. */ + + /** + * Position to the south. + */ + public static final int SOUTH = 15; + + /** + * Position to the southwest. + */ public static final int SOUTHWEST = 16; - /** Position to the west. */ + + /** + * Position to the west. + */ public static final int WEST = 17; - /** Occupy all remaining cells except last cell. */ + /** + * Position to the northwest. + */ + public static final int NORTHWEST = 18; + + // gridx and gridy values. + /** + * Occupy all remaining cells except last cell. + */ public static final int RELATIVE = -1; - /** Occupy all remaining cells. */ - public static final int REMAINDER = 0; /** - * Position to where the first text line would end. Equals to NORTHEAST for - * horizontal left-to-right orientations. + * Occupy all remaining cells. */ - public static final int FIRST_LINE_END = 24; + public static final int REMAINDER = 0; /** - * Position to where the first text line would start. Equals to NORTHWEST for - * horizontal left-to-right orientations. + * Position to where a page starts. Equals NORTH for horizontal orientations. */ - public static final int FIRST_LINE_START = 23; + public static final int PAGE_START = 19; /** - * Position to where the last text line would end. Equals to SOUTHEAST for - * horizontal left-to-right orientations. + * Position to where a page ends. Equals SOUTH for horizontal orientations. */ - public static final int LAST_LINE_END = 26; + public static final int PAGE_END = 20; /** - * Position to where the last text line would start. Equals to SOUTHWEST for - * horizontal left-to-right orientations. + * Position to where a text line would start. Equals to WEST for + * left-to-right orientations. */ - public static final int LAST_LINE_START = 25; + public static final int LINE_START = 21; /** * Position to where a text line would end. Equals to EAST for @@ -112,20 +149,28 @@ public class GridBagConstraints implements Cloneable, Serializable public static final int LINE_END = 22; /** - * Position to where a text line would start. Equals to WEST for - * left-to-right orientations. + * Position to where the first text line would start. Equals to NORTHWEST for + * horizontal left-to-right orientations. */ - public static final int LINE_START = 21; + public static final int FIRST_LINE_START = 23; /** - * Position to where a page ends. Equals SOUTH for horizontal orientations. + * Position to where the first text line would end. Equals to NORTHEAST for + * horizontal left-to-right orientations. */ - public static final int PAGE_END = 20; + public static final int FIRST_LINE_END = 24; /** - * Position to where a page starts. Equals NORTH for horizontal orientations. + * Position to where the last text line would start. Equals to SOUTHWEST for + * horizontal left-to-right orientations. */ - public static final int PAGE_START = 19; + public static final int LAST_LINE_START = 25; + + /** + * Position to where the last text line would end. Equals to SOUTHEAST for + * horizontal left-to-right orientations. + */ + public static final int LAST_LINE_END = 26; public int anchor; public int fill; @@ -139,7 +184,9 @@ public class GridBagConstraints implements Cloneable, Serializable public double weightx; public double weighty; - /** Create a copy of this object. */ + /** + * Create a copy of this object. + */ public Object clone () { try @@ -155,8 +202,10 @@ public class GridBagConstraints implements Cloneable, Serializable } } - /** Create a new GridBagConstraints object with the default - * parameters. */ + /** + * Create a new GridBagConstraints object with the default + * parameters. + */ public GridBagConstraints () { this.anchor = CENTER; @@ -172,8 +221,10 @@ public class GridBagConstraints implements Cloneable, Serializable this.weighty = 0; } - /** Create a new GridBagConstraints object with the indicated - * parameters. */ + /** + * Create a new GridBagConstraints object with the indicated + * parameters. + */ public GridBagConstraints (int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, diff --git a/java/awt/GridBagLayout.java b/java/awt/GridBagLayout.java index 20c402b78..c8d204396 100644 --- a/java/awt/GridBagLayout.java +++ b/java/awt/GridBagLayout.java @@ -38,8 +38,6 @@ exception statement from your version. */ package java.awt; -import gnu.classpath.NotImplementedException; - import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; @@ -323,13 +321,127 @@ public class GridBagLayout } /** - * Obsolete. + * Move and resize a rectangle according to a set of grid bag + * constraints. The x, y, width and height fields of the + * rectangle argument are adjusted to the new values. + * + * @param constraints position and size constraints + * @param r rectangle to be moved and resized */ - protected void AdjustForGravity (GridBagConstraints gbc, Rectangle rect) - throws NotImplementedException + protected void AdjustForGravity (GridBagConstraints constraints, + Rectangle r) { - // FIXME - throw new Error ("Not implemented"); + Rectangle result = new Rectangle (0, 0, 0, 0); + + // Calculate width and height. + + // Adjust width and height for fill value. + switch (constraints.fill) + { + case GridBagConstraints.NONE: + result.width = 0; + result.height = 0; + break; + case GridBagConstraints.BOTH: + result.width = r.width; + result.height = r.height; + break; + case GridBagConstraints.HORIZONTAL: + result.width = r.width; + result.height = 0; + break; + case GridBagConstraints.VERTICAL: + result.width = 0; + result.height = r.height; + break; + } + + // Adjust width and height for insets, and clamp to minimum + // values of ipadx and ipady. + result.width = Math.max(result.width + - constraints.insets.left + - constraints.insets.right, + constraints.ipadx); + result.height = Math.max(result.height + - constraints.insets.top + - constraints.insets.bottom, + constraints.ipady); + + // Calculate x and y. + + // Do not account for the internal padding when setting the + // result rectangle's x and y co-ordinates. + int rect_width = r.width - constraints.ipadx; + int rect_height = r.height - constraints.ipady; + + int half_width = (rect_width + constraints.insets.left + - constraints.insets.right) / 2; + int half_height = (rect_height + constraints.insets.top + - constraints.insets.bottom) / 2; + + // Adjust x and y for anchor value. + switch (constraints.anchor) + { + case GridBagConstraints.CENTER: + result.x = r.x + half_width; + result.y = r.y + half_height; + break; + case GridBagConstraints.NORTH: + result.x = r.x + half_width; + result.y = r.y + constraints.insets.top; + break; + case GridBagConstraints.NORTHEAST: + result.x = r.x + rect_width - constraints.insets.right; + result.y = r.y + constraints.insets.top; + break; + case GridBagConstraints.EAST: + result.x = r.x + rect_width - constraints.insets.right; + result.y = r.y + half_height; + break; + case GridBagConstraints.SOUTHEAST: + result.x = r.x + rect_width - constraints.insets.right; + result.y = r.y + rect_height - constraints.insets.bottom; + break; + case GridBagConstraints.SOUTH: + result.x = r.x + half_width; + result.y = r.y + rect_height - constraints.insets.bottom; + break; + case GridBagConstraints.SOUTHWEST: + result.x = r.x + constraints.insets.left; + result.y = r.y + rect_height - constraints.insets.bottom; + break; + case GridBagConstraints.WEST: + result.x = r.x + constraints.insets.left; + result.y = r.y + half_height; + break; + case GridBagConstraints.NORTHWEST: + result.x = r.x + constraints.insets.left; + result.y = r.y + constraints.insets.top; + break; + } + + // Adjust x and y for fill, clamping values to the external + // padding boundaries where necessary. + switch (constraints.fill) + { + case GridBagConstraints.NONE: + break; + case GridBagConstraints.BOTH: + result.x = r.x + constraints.insets.left; + result.y = r.y + constraints.insets.top; + break; + case GridBagConstraints.HORIZONTAL: + result.x = r.x + constraints.insets.left; + break; + case GridBagConstraints.VERTICAL: + result.y = r.y + constraints.insets.top; + break; + } + + r.x = result.x; + r.y = result.y; + r.width = result.width; + r.height = result.height; } /** @@ -354,10 +466,9 @@ public class GridBagLayout // layoutInfo. So we wait until after this for loop to set // layoutInfo. Component lastComp = null; - int cellx = 0; - int celly = 0; - int cellw = 0; - int cellh = 0; + + Rectangle cell = new Rectangle(); + for (int i = 0; i < components.length; i++) { Component component = components[i]; @@ -371,29 +482,23 @@ public class GridBagLayout if (lastComp != null && constraints.gridheight == GridBagConstraints.REMAINDER) - celly += cellh; + cell.y += cell.height; else - celly = sumIntArray(info.rowHeights, constraints.gridy); + cell.y = sumIntArray(info.rowHeights, constraints.gridy); if (lastComp != null && constraints.gridwidth == GridBagConstraints.REMAINDER) - cellx += cellw; + cell.x += cell.width; else - cellx = sumIntArray(info.colWidths, constraints.gridx); + cell.x = sumIntArray(info.colWidths, constraints.gridx); - cellw = sumIntArray(info.colWidths, constraints.gridx - + constraints.gridwidth) - cellx; - cellh = sumIntArray(info.rowHeights, constraints.gridy - + constraints.gridheight) - celly; - - Insets insets = constraints.insets; - if (insets != null) - { - cellx += insets.left; - celly += insets.top; - cellw -= insets.left + insets.right; - cellh -= insets.top + insets.bottom; - } + cell.width = sumIntArray(info.colWidths, constraints.gridx + + constraints.gridwidth) - cell.x; + cell.height = sumIntArray(info.rowHeights, constraints.gridy + + constraints.gridheight) - cell.y; + + // Adjust for insets. + AdjustForGravity( constraints, cell ); // Note: Documentation says that padding is added on both sides, but // visual inspection shows that the Sun implementation only adds it @@ -404,14 +509,14 @@ public class GridBagLayout switch (constraints.fill) { case GridBagConstraints.HORIZONTAL: - dim.width = cellw; + dim.width = cell.width; break; case GridBagConstraints.VERTICAL: - dim.height = cellh; + dim.height = cell.height; break; case GridBagConstraints.BOTH: - dim.width = cellw; - dim.height = cellh; + dim.width = cell.width; + dim.height = cell.height; break; } @@ -421,40 +526,40 @@ public class GridBagLayout switch (constraints.anchor) { case GridBagConstraints.NORTH: - x = cellx + (cellw - dim.width) / 2; - y = celly; + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y; break; case GridBagConstraints.SOUTH: - x = cellx + (cellw - dim.width) / 2; - y = celly + cellh - dim.height; + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y + cell.height - dim.height; break; case GridBagConstraints.WEST: - x = cellx; - y = celly + (cellh - dim.height) / 2; + x = cell.x; + y = cell.y + (cell.height - dim.height) / 2; break; case GridBagConstraints.EAST: - x = cellx + cellw - dim.width; - y = celly + (cellh - dim.height) / 2; + x = cell.x + cell.width - dim.width; + y = cell.y + (cell.height - dim.height) / 2; break; case GridBagConstraints.NORTHEAST: - x = cellx + cellw - dim.width; - y = celly; + x = cell.x + cell.width - dim.width; + y = cell.y; break; case GridBagConstraints.NORTHWEST: - x = cellx; - y = celly; + x = cell.x; + y = cell.y; break; case GridBagConstraints.SOUTHEAST: - x = cellx + cellw - dim.width; - y = celly + cellh - dim.height; + x = cell.x + cell.width - dim.width; + y = cell.y + cell.height - dim.height; break; case GridBagConstraints.SOUTHWEST: - x = cellx; - y = celly + cellh - dim.height; + x = cell.x; + y = cell.y + cell.height - dim.height; break; default: - x = cellx + (cellw - dim.width) / 2; - y = celly + (cellh - dim.height) / 2; + x = cell.x + (cell.width - dim.width) / 2; + y = cell.y + (cell.height - dim.height) / 2; break; } component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, @@ -1086,10 +1191,18 @@ public class GridBagLayout } /** + * Move and resize a rectangle according to a set of grid bag + * constraints. The x, y, width and height fields of the + * rectangle argument are adjusted to the new values. + * + * @param constraints position and size constraints + * @param r rectangle to be moved and resized + * * @since 1.4 */ - protected void adjustForGravity (GridBagConstraints gbc, Rectangle rect) + protected void adjustForGravity (GridBagConstraints constraints, + Rectangle r) { - AdjustForGravity (gbc, rect); + AdjustForGravity (constraints, r); } } diff --git a/java/awt/Insets.java b/java/awt/Insets.java index 6d5bd122e..762b6975b 100644 --- a/java/awt/Insets.java +++ b/java/awt/Insets.java @@ -1,5 +1,5 @@ /* Insets.java -- information about a container border - Copyright (C) 1999, 2000, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -149,14 +149,13 @@ public class Insets implements Cloneable, Serializable /** * Returns a string representation of this object, which will be non-null. - * The format is unspecified, but appears to be <code>XXX what is it?</code>. * * @return a string representation of this object */ public String toString() { - return getClass().getName() + "(top=" + top + ",bottom=" + bottom + - ",left=" + left + ",right=" + right + ')'; + return getClass().getName() + "[top=" + top + ",left=" + left + + ",bottom=" + bottom + ",right=" + right + ']'; } /** diff --git a/java/awt/Label.java b/java/awt/Label.java index d6db32910..71614da64 100644 --- a/java/awt/Label.java +++ b/java/awt/Label.java @@ -1,5 +1,6 @@ /* Label.java -- Java label widget - Copyright (C) 1999, 2000, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006, Free Software + Foundation, Inc. This file is part of GNU Classpath. @@ -45,275 +46,250 @@ import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; /** - * This component is used for displaying simple text strings that cannot - * be edited by the user. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - * @author Tom Tromey (tromey@cygnus.com) - * @author Andrew John Hughes (gnu_andrew@member.fsf.org) - */ + * This component is used for displaying simple text strings that cannot + * be edited by the user. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ public class Label extends Component implements Accessible { -/* - * Static Variables - */ - -/** - * Alignment constant aligning the text to the left of its window. - */ -public static final int LEFT = 0; - -/** - * Alignment constant aligning the text in the center of its window. - */ -public static final int CENTER = 1; - -/** - * Alignment constant aligning the text to the right of its window. - */ -public static final int RIGHT = 2; - -// Serialization version constant: -private static final long serialVersionUID = 3094126758329070636L; - -/*************************************************************************/ + /** + * Alignment constant aligning the text to the left of its window. + */ + public static final int LEFT = 0; -/* - * Instance Variables - */ + /** + * Alignment constant aligning the text in the center of its window. + */ + public static final int CENTER = 1; -/** - * @serial Indicates the alignment of the text within this label's window. - * This is one of the constants in this class. The default value is - * <code>LEFT</code>. - */ -private int alignment; + /** + * Alignment constant aligning the text to the right of its window. + */ + public static final int RIGHT = 2; -/** - * @serial The text displayed in the label - */ -private String text; + // Serialization version constant: + private static final long serialVersionUID = 3094126758329070636L; -/*************************************************************************/ + /** + * @serial Indicates the alignment of the text within this label's window. + * This is one of the constants in this class. The default value is + * <code>LEFT</code>. + */ + private int alignment; -/* - * Constructors - */ + /** + * @serial The text displayed in the label + */ + private String text; -/** - * Initializes a new instance of <code>Label</code> with no text. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -Label() -{ - this("", LEFT); -} + /** + * Initializes a new instance of <code>Label</code> with no text. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label() + { + this("", LEFT); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>Label</code> with the specified + * text that is aligned to the left. + * + * @param text The text of the label. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label(String text) + { + this(text, LEFT); + } -/** - * Initializes a new instance of <code>Label</code> with the specified - * text that is aligned to the left. - * - * @param text The text of the label. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -Label(String text) -{ - this(text, LEFT); -} + /** + * Initializes a new instance of <code>Label</code> with the specified + * text and alignment. + * + * @param text The text of the label. + * @param alignment The desired alignment for the text in this label, + * which must be one of <code>LEFT</code>, <code>CENTER</code>, or + * <code>RIGHT</code>. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + */ + public Label(String text, int alignment) + { + setAlignment(alignment); + setText(text); -/*************************************************************************/ + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } -/** - * Initializes a new instance of <code>Label</code> with the specified - * text and alignment. - * - * @param text The text of the label. - * @param alignment The desired alignment for the text in this label, - * which must be one of <code>LEFT</code>, <code>CENTER</code>, or - * <code>RIGHT</code>. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -Label(String text, int alignment) -{ - setAlignment (alignment); - setText (text); + /** + * Returns the constant indicating the alignment of the text in this + * label. The value returned will be one of the alignment constants + * from this class. + * + * @return The alignment of the text in the label. + */ + public int getAlignment() + { + return(alignment); + } - if (GraphicsEnvironment.isHeadless()) - throw new HeadlessException (); -} + /** + * Sets the text alignment of this label to the specified value. + * + * @param alignment The desired alignment for the text in this label, + * which must be one of <code>LEFT</code>, <code>CENTER</code>, or + * <code>RIGHT</code>. + */ + public synchronized void setAlignment(int alignment) + { + if (alignment != CENTER && alignment != LEFT && alignment != RIGHT) + throw new IllegalArgumentException("invalid alignment: " + alignment); + this.alignment = alignment; + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setAlignment(alignment); + } + } -/*************************************************************************/ + /** + * Returns the text displayed in this label. + * + * @return The text for this label. + */ + public String getText() + { + return text; + } -/* - * Instance Variables - */ + /** + * Sets the text in this label to the specified value. + * + * @param text The new text for this label. + */ + public synchronized void setText(String text) + { + if ((this.text == null && text != null) + || (this.text != null && ! this.text.equals(text))) + { + this.text = text; + + if (peer != null) + { + LabelPeer lp = (LabelPeer) peer; + lp.setText(text); + } + invalidate(); + } + } -/** - * Returns the constant indicating the alignment of the text in this - * label. The value returned will be one of the alignment constants - * from this class. - * - * @return The alignment of the text in the label. - */ -public int -getAlignment() -{ - return(alignment); -} + /** + * Notifies this label that it has been added to a container, causing + * the peer to be created. This method is called internally by the AWT + * system. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit().createLabel(this); + super.addNotify(); + } -/*************************************************************************/ + /** + * Returns a parameter string useful for debugging. + * + * @return A debugging string. + */ + protected String paramString() + { + return ("text=" + getText() + ",alignment=" + + getAlignment() + "," + super.paramString()); + } -/** - * Sets the text alignment of this label to the specified value. - * - * @param alignment The desired alignment for the text in this label, - * which must be one of <code>LEFT</code>, <code>CENTER</code>, or - * <code>RIGHT</code>. - */ -public synchronized void -setAlignment(int alignment) -{ - if (alignment != CENTER && alignment != LEFT && alignment != RIGHT) - throw new IllegalArgumentException ("invalid alignment: " + alignment); - this.alignment = alignment; - if (peer != null) + /** + * This class provides accessibility support for the label. + */ + protected class AccessibleAWTLabel + extends AccessibleAWTComponent + { + /** + * For compatability with Sun's JDK 1.4.2 rev. 5 + */ + private static final long serialVersionUID = -3568967560160480438L; + + /** + * Constructor for the accessible label. + */ + public AccessibleAWTLabel() { - LabelPeer lp = (LabelPeer) peer; - lp.setAlignment (alignment); } -} - -/*************************************************************************/ - -/** - * Returns the text displayed in this label. - * - * @return The text for this label. - */ -public String -getText() -{ - return(text); -} - -/*************************************************************************/ -/** - * Sets the text in this label to the specified value. - * - * @param text The new text for this label. - */ -public synchronized void -setText(String text) -{ - if ((this.text == null && text != null) - || (this.text != null && ! this.text.equals(text))) + /** + * Returns the accessible name for the label. This is + * the text used in the label. + * + * @return a <code>String</code> containing the accessible + * name for this label. + */ + public String getAccessibleName() { - this.text = text; - - if (peer != null) - { - LabelPeer lp = (LabelPeer) peer; - lp.setText (text); - } - invalidate(); + return getText(); } -} - -/*************************************************************************/ - -/** - * Notifies this label that it has been added to a container, causing - * the peer to be created. This method is called internally by the AWT - * system. - */ -public void -addNotify() -{ - if (peer == null) - peer = getToolkit ().createLabel (this); - super.addNotify (); -} -/*************************************************************************/ - -/** - * Returns a parameter string useful for debugging. - * - * @return A debugging string. - */ -protected String -paramString() -{ - return ("text=" + getText() + ",alignment=" + - getAlignment() + "," + super.paramString()); -} + /** + * Returns the accessible role for the label. + * + * @return an instance of <code>AccessibleRole</code>, describing + * the role of the label. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.LABEL; + } -/** - * This class provides accessibility support for the label. - */ -protected class AccessibleAWTLabel - extends AccessibleAWTComponent -{ - /** - * For compatability with Sun's JDK 1.4.2 rev. 5 - */ - private static final long serialVersionUID = -3568967560160480438L; + } /** - * Constructor for the accessible label. + * Gets the AccessibleContext associated with this <code>Label</code>. + * The context is created, if necessary. + * + * @return the associated context */ - public AccessibleAWTLabel() + public AccessibleContext getAccessibleContext() { + /* Create the context if this is the first request */ + if (accessibleContext == null) + accessibleContext = new AccessibleAWTLabel(); + return accessibleContext; } /** - * Returns the accessible name for the label. This is - * the text used in the label. + * Generate a unique name for this button. * - * @return a <code>String</code> containing the accessible - * name for this label. + * @return A unique name for this button. */ - public String getAccessibleName() + String generateName() { - return getText(); + return "label" + getUniqueLong(); } - + /** - * Returns the accessible role for the label. - * - * @return an instance of <code>AccessibleRole</code>, describing - * the role of the label. + * The number used to generate the name returned by getName. */ - public AccessibleRole getAccessibleRole() + private static transient long nextLabelNumber; + + private static synchronized long getUniqueLong() { - return AccessibleRole.LABEL; + return nextLabelNumber++; } } -/** - * Gets the AccessibleContext associated with this <code>Label</code>. - * The context is created, if necessary. - * - * @return the associated context - */ -public AccessibleContext getAccessibleContext() -{ - /* Create the context if this is the first request */ - if (accessibleContext == null) - accessibleContext = new AccessibleAWTLabel(); - return accessibleContext; -} - -} // class Label - diff --git a/java/awt/List.java b/java/awt/List.java index 808c4b6ed..1d703e5a6 100644 --- a/java/awt/List.java +++ b/java/awt/List.java @@ -161,7 +161,11 @@ List(int rows) public List(int rows, boolean multipleMode) { - this.rows = rows; + if (rows == 0) + this.rows = 4; + else + this.rows = rows; + this.multipleMode = multipleMode; selected = new int[0]; @@ -645,13 +649,13 @@ clear() * @param item The new item value. * @param index The index of the item to replace. * - * @exception IllegalArgumentException If the index is not valid. + * @exception ArrayIndexOutOfBoundsException If the index is not valid. */ public synchronized void -replaceItem(String item, int index) throws IllegalArgumentException +replaceItem(String item, int index) throws ArrayIndexOutOfBoundsException { if ((index < 0) || (index >= items.size())) - throw new IllegalArgumentException("Bad list index: " + index); + throw new ArrayIndexOutOfBoundsException("Bad list index: " + index); items.insertElementAt(item, index + 1); items.removeElementAt (index); @@ -818,15 +822,11 @@ isSelected(int index) /** * This method ensures that the item at the specified index is visible. * - * @exception IllegalArgumentException If the specified index is out of - * range. + * @param index The index of the item to be made visible. */ public synchronized void makeVisible(int index) throws IllegalArgumentException { - if ((index < 0) || (index >= items.size())) - throw new IllegalArgumentException("Bad list index: " + index); - visibleIndex = index; if (peer != null) { diff --git a/java/awt/Point.java b/java/awt/Point.java index 31b72e2cc..64bc07eaf 100644 --- a/java/awt/Point.java +++ b/java/awt/Point.java @@ -1,5 +1,5 @@ /* Point.java -- represents a point in 2-D space - Copyright (C) 1999, 2002 Free Software Foundation + Copyright (C) 1999, 2002, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -83,7 +83,7 @@ public class Point extends Point2D implements Serializable /** * Initializes a new instance of <code>Point</code> representing the - * coordiates (0,0). + * coordinates (0, 0). * * @since 1.1 */ @@ -93,7 +93,7 @@ public class Point extends Point2D implements Serializable /** * Initializes a new instance of <code>Point</code> with coordinates - * identical to the coordinates of the specified points. + * identical to the coordinates of the specified point. * * @param p the point to copy the coordinates from * @throws NullPointerException if p is null @@ -178,15 +178,16 @@ public class Point extends Point2D implements Serializable /** * Sets this object's coordinates to the specified values. This method - * performs normal casting from double to int, so you may lose precision. + * rounds to the nearest integer coordinates by adding 0.5 and calling + * {@link Math#floor(double)}. * * @param x the new X coordinate * @param y the new Y coordinate */ public void setLocation(double x, double y) { - this.x = (int) x; - this.y = (int) y; + this.x = (int) Math.floor(x + 0.5); + this.y = (int) Math.floor(y + 0.5); } /** diff --git a/java/awt/TextField.java b/java/awt/TextField.java index ff32afa88..45be0ea51 100644 --- a/java/awt/TextField.java +++ b/java/awt/TextField.java @@ -96,7 +96,7 @@ private ActionListener action_listeners; public TextField() { - this("", 1); + this("", 0); } /*************************************************************************/ @@ -113,7 +113,7 @@ TextField() public TextField(String text) { - this(text, text.length()); + this(text, (text == null) ? 0 : text.length()); } /*************************************************************************/ @@ -147,7 +147,11 @@ public TextField(String text, int columns) { super(text); - this.columns = columns; + + if (columns < 0) + this.columns = 0; + else + this.columns = columns; if (GraphicsEnvironment.isHeadless()) throw new HeadlessException (); diff --git a/java/awt/Toolkit.java b/java/awt/Toolkit.java index 99863fab0..e2db04837 100644 --- a/java/awt/Toolkit.java +++ b/java/awt/Toolkit.java @@ -698,6 +698,14 @@ public abstract class Toolkit public PrintJob getPrintJob(Frame frame, String title, JobAttributes jobAttr, PageAttributes pageAttr) { + // FIXME: it is possible this check may be removed + // if this method, when written, always delegates to + // getPrintJob(Frame, String, Properties). + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + return null; } diff --git a/java/awt/datatransfer/Clipboard.java b/java/awt/datatransfer/Clipboard.java index 5fa1d1ab1..2029e2c35 100644 --- a/java/awt/datatransfer/Clipboard.java +++ b/java/awt/datatransfer/Clipboard.java @@ -1,5 +1,5 @@ /* Clipboard.java -- Class for transferring data via cut and paste. - Copyright (C) 1999, 2001, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2001, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -182,6 +182,9 @@ public class Clipboard public void addFlavorListener(FlavorListener listener) { + if (listener == null) + return; + synchronized(listeners) { listeners.add(listener); @@ -190,6 +193,9 @@ public class Clipboard public void removeFlavorListener(FlavorListener listener) { + if (listener == null) + return; + synchronized(listeners) { listeners.remove(listener); diff --git a/java/awt/datatransfer/DataFlavor.java b/java/awt/datatransfer/DataFlavor.java index 33b98379c..63a00db13 100644 --- a/java/awt/datatransfer/DataFlavor.java +++ b/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, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -47,6 +47,7 @@ import java.io.InputStreamReader; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Reader; +import java.io.Serializable; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; @@ -197,31 +198,37 @@ public class DataFlavor implements java.io.Externalizable, Cloneable throw new ClassNotFoundException(className); } - private static Class getRepresentationClassFromMime(String mimeString, + private static Class getRepresentationClassFromMimeThrows(String mimeString, ClassLoader classLoader) + throws ClassNotFoundException { String classname = getParameter("class", mimeString); if (classname != null) - { - try - { - return tryToLoadClass(classname, classLoader); - } - catch(Exception e) - { - IllegalArgumentException iae; - iae = new IllegalArgumentException("mimeString: " - + mimeString - + " classLoader: " - + classLoader); - iae.initCause(e); - throw iae; - } - } + return tryToLoadClass(classname, classLoader); else return java.io.InputStream.class; } - + + // Same as above, but wraps any ClassNotFoundExceptions + private static Class getRepresentationClassFromMime(String mimeString, + ClassLoader classLoader) + { + try + { + return getRepresentationClassFromMimeThrows(mimeString, classLoader); + } + catch(ClassNotFoundException cnfe) + { + IllegalArgumentException iae; + iae = new IllegalArgumentException("mimeString: " + + mimeString + + " classLoader: " + + classLoader); + iae.initCause(cnfe); + throw iae; + } + } + /** * Returns the value of the named MIME type parameter, or <code>null</code> * if the parameter does not exist. Given the parameter name and the mime @@ -240,7 +247,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable String value = mimeString.substring(idx + paramName.length() + 1); - idx = value.indexOf(" "); + idx = value.indexOf(";"); if (idx == -1) return(value); else @@ -328,6 +335,14 @@ public class DataFlavor implements java.io.Externalizable, Cloneable { this.representationClass = representationClass; this.mimeType = mimeType; + + // Do some simple validity checks + String type = getPrimaryType() + "/" + getSubType(); + if (type.indexOf(' ') != -1 + || type.indexOf('=') != -1 + || type.indexOf(';') != -1) + throw new IllegalArgumentException(mimeType); + if (humanPresentableName != null) this.humanPresentableName = humanPresentableName; else @@ -375,7 +390,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable ClassLoader classLoader) throws ClassNotFoundException { - this(getRepresentationClassFromMime(mimeType, classLoader), + this(getRepresentationClassFromMimeThrows(mimeType, classLoader), mimeType, humanPresentableName); } @@ -417,7 +432,8 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ public DataFlavor(String mimeType) throws ClassNotFoundException { - this(mimeType, null); + this(getRepresentationClassFromMimeThrows(mimeType, null), + mimeType, null); } /** @@ -567,7 +583,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ public boolean isRepresentationClassInputStream() { - return representationClass.getName().equals("java.io.InputStream"); + return InputStream.class.isAssignableFrom(representationClass); } /** @@ -579,17 +595,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ 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; + return Serializable.class.isAssignableFrom(representationClass); } /** @@ -634,8 +640,10 @@ public class DataFlavor implements java.io.Externalizable, Cloneable */ public boolean isFlavorJavaFileListType() { - if (mimeType.equals(javaFileListFlavor.mimeType) - && representationClass.equals(javaFileListFlavor.representationClass)) + if (getPrimaryType().equals(javaFileListFlavor.getPrimaryType()) + && getSubType().equals(javaFileListFlavor.getSubType()) + && javaFileListFlavor.representationClass + .isAssignableFrom(representationClass)) return true; return false ; @@ -666,7 +674,11 @@ public class DataFlavor implements java.io.Externalizable, Cloneable /** * This method test the specified <code>DataFlavor</code> for equality * against this object. This will be true if the MIME type and - * representation type are the equal. + * representation class are the equal. If the primary type is 'text' + * then also the value of the charset parameter is compared. In such a + * case when the charset parameter isn't given then the charset is + * assumed to be equal to the default charset of the platform. All + * other parameters are ignored. * * @param flavor The <code>DataFlavor</code> to test against. * @@ -677,12 +689,34 @@ public class DataFlavor implements java.io.Externalizable, Cloneable { if (flavor == null) return false; - - if (! this.mimeType.toLowerCase().equals(flavor.mimeType.toLowerCase())) + + String primary = getPrimaryType(); + if (! primary.equals(flavor.getPrimaryType())) return false; - + + String sub = getSubType(); + if (! sub.equals(flavor.getSubType())) + return false; + if (! this.representationClass.equals(flavor.representationClass)) return false; + + if (primary.equals("text")) + if (! isRepresentationClassCharBuffer() + && ! isRepresentationClassReader() + && representationClass != java.lang.String.class + && ! (representationClass.isArray() + && representationClass.getComponentType() == Character.TYPE)) + { + String charset = getParameter("charset"); + String otherset = flavor.getParameter("charset"); + String defaultset = Charset.defaultCharset().name(); + + if (charset == null || charset.equals(defaultset)) + return (otherset == null || otherset.equals(defaultset)); + + return charset.equals(otherset); + } return true; } diff --git a/java/awt/event/KeyEvent.java b/java/awt/event/KeyEvent.java index d4b93ba3e..42084d733 100644 --- a/java/awt/event/KeyEvent.java +++ b/java/awt/event/KeyEvent.java @@ -993,6 +993,27 @@ public class KeyEvent extends InputEvent public static final int VK_ALT_GRAPH = 65406; /** + * The 'begin' key VK_BEGIN + * + * @since 1.5 + */ + public static final int VK_BEGIN = 65368; + + /** + * The context-menu key VK_CONTEXT_MENU + * + * @since 1.5 + */ + public static final int VK_CONTEXT_MENU = 525; + + /** + * The 'Windows' key VK_WINDOWS + * + * @since 1.5 + */ + public static final int VK_WINDOWS = 524; + + /** * The virtual key VK_UNDEFINED. This is used for key typed events, which * do not have a virtual key. */ diff --git a/java/awt/font/FontRenderContext.java b/java/awt/font/FontRenderContext.java index 78564a647..c50e5e509 100644 --- a/java/awt/font/FontRenderContext.java +++ b/java/awt/font/FontRenderContext.java @@ -83,7 +83,15 @@ public class FontRenderContext public boolean equals (FontRenderContext rhs) { - return (affineTransform.equals (rhs.getTransform ()) + if (rhs == null) + return false; + + if (affineTransform == null && rhs.affineTransform != null + || affineTransform != null && rhs.affineTransform == null) + return false; + + return ((affineTransform == rhs.affineTransform + || affineTransform.equals (rhs.getTransform ())) && isAntiAliased == rhs.isAntiAliased () && usesFractionalMetrics == rhs.usesFractionalMetrics ()); } diff --git a/java/awt/font/LineBreakMeasurer.java b/java/awt/font/LineBreakMeasurer.java index c2a6d45d9..816c7745c 100644 --- a/java/awt/font/LineBreakMeasurer.java +++ b/java/awt/font/LineBreakMeasurer.java @@ -41,57 +41,41 @@ package java.awt.font; import java.text.AttributedCharacterIterator; import java.text.AttributedString; import java.text.BreakIterator; -import java.awt.font.TextLayout; -import java.awt.font.FontRenderContext; import java.awt.Shape; public final class LineBreakMeasurer { private AttributedCharacterIterator text; private int position; - private FontRenderContext frc; - private TextLayout totalLayout; + private TextMeasurer tm; private int numChars; public LineBreakMeasurer(AttributedCharacterIterator text, BreakIterator breakIter, FontRenderContext frc) { - this.text = text; - this.frc = frc; - position = 0; - totalLayout = new TextLayout(text, frc); - numChars = totalLayout.getCharacterCount(); + this( text, frc ); } public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { this.text = text; - this.frc = frc; position = 0; - totalLayout = new TextLayout(text, frc); - numChars = totalLayout.getCharacterCount(); + numChars = text.getEndIndex(); + tm = new TextMeasurer( text, frc ); } public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) { - totalLayout = new TextLayout(newParagraph, frc); - if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() ) - throw new NullPointerException("Invalid deletePos:"+deletePos); - numChars = totalLayout.getCharacterCount(); - text = newParagraph; + tm.deleteChar( newParagraph, deletePos ); position = 0; } public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) { - totalLayout = new TextLayout(newParagraph, frc); - if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() ) - throw new NullPointerException("Invalid insertPos:"+insertPos); - numChars = totalLayout.getCharacterCount(); - text = newParagraph; + tm.insertChar( newParagraph, insertPos ); position = 0; } @@ -104,11 +88,9 @@ public final class LineBreakMeasurer boolean requireNextWord) { int next = nextOffset( wrappingWidth, offsetLimit, requireNextWord ); - AttributedCharacterIterator aci = (new AttributedString( text, - position, next ) - ).getIterator(); + TextLayout tl = tm.getLayout( position, next ); position = next; - return new TextLayout( aci, frc ); + return tl; } public int nextOffset(float wrappingWidth) @@ -119,69 +101,40 @@ public final class LineBreakMeasurer public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) { - Shape s = totalLayout.getBlackBoxBounds( position, offsetLimit ); - double remainingLength = s.getBounds2D().getWidth(); + int guessOffset = tm.getLineBreakIndex(position, wrappingWidth); + if( offsetLimit > numChars ) + offsetLimit = numChars; - int guessOffset = (int)( ( (double)wrappingWidth / (double)remainingLength) - * ( (double)numChars - (double)position ) ); - guessOffset += position; if( guessOffset > offsetLimit ) - guessOffset = offsetLimit; - - s = totalLayout.getBlackBoxBounds( position, guessOffset ); - double guessLength = s.getBounds2D().getWidth(); - - boolean makeSmaller = ( guessLength > wrappingWidth ); - int inc = makeSmaller ? -1 : 1; - boolean keepGoing = true; - - do { - guessOffset = guessOffset + inc; - if( guessOffset <= position || guessOffset > offsetLimit ) - { - keepGoing = false; - } - else - { - s = totalLayout.getBlackBoxBounds( position, guessOffset ); - guessLength = s.getBounds2D().getWidth(); - if( makeSmaller && ( guessLength <= wrappingWidth) ) - keepGoing = false; - if( !makeSmaller && ( guessLength >= wrappingWidth) ) - keepGoing = false; - } + text.setIndex( offsetLimit ); + return offsetLimit; } - while( keepGoing ); - if( !makeSmaller ) - guessOffset--; + text.setIndex( guessOffset ); - if( guessOffset >= offsetLimit ) - return offsetLimit; + // If we're on a breaking character, return directly + if( Character.isWhitespace( text.current() ) ) + return guessOffset; - text.setIndex( guessOffset ); + // Otherwise jump forward or backward to the last such char. if( !requireNextWord ) - { - char c = text.previous(); - while( !Character.isWhitespace( c ) && c != '-' && - guessOffset > position ) - { - guessOffset--; - c = text.previous(); - } - } + while( !Character.isWhitespace( text.previous() ) && + guessOffset > position ) + guessOffset--; else + while( !Character.isWhitespace( text.next() ) && + guessOffset < offsetLimit ) + guessOffset++; + + if( guessOffset > offsetLimit ) { - char c = text.next(); - while( !Character.isWhitespace( c ) && c != '-' && - guessOffset < offsetLimit ) - { - guessOffset++; - c = text.next(); - } + text.setIndex( offsetLimit ); + return offsetLimit; } + text.setIndex( guessOffset ); + return guessOffset; } diff --git a/java/awt/font/TextLayout.java b/java/awt/font/TextLayout.java index a55aab235..9b85d7003 100644 --- a/java/awt/font/TextLayout.java +++ b/java/awt/font/TextLayout.java @@ -47,6 +47,7 @@ import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; +import java.text.CharacterIterator; import java.text.AttributedCharacterIterator; import java.text.Bidi; import java.util.Map; @@ -71,6 +72,12 @@ public final class TextLayout implements Cloneable private int[][] runIndices; /** + * Character indices. + * Fixt index is the glyphvector, second index is the (first) glyph. + */ + private int[][] charIndices; + + /** * Base directionality, determined from the first char. */ private boolean leftToRight; @@ -137,6 +144,7 @@ public final class TextLayout implements Cloneable Font.LAYOUT_LEFT_TO_RIGHT : Font.LAYOUT_RIGHT_TO_LEFT ); } + setCharIndices(); } public TextLayout (String string, @@ -147,9 +155,97 @@ public final class TextLayout implements Cloneable } public TextLayout (AttributedCharacterIterator text, FontRenderContext frc) - throws NotImplementedException { - throw new Error ("not implemented"); + // FIXME: Very rudimentary. + this(getText(text), getFont(text), frc); + } + + /** + * Package-private constructor to make a textlayout from an existing one. + * This is used by TextMeasurer for returning sub-layouts, and it + * saves a lot of time in not having to relayout the text. + */ + TextLayout(TextLayout t, int startIndex, int endIndex) + { + font = t.font; + frc = t.frc; + boundsCache = null; + lm = t.lm; + leftToRight = t.leftToRight; + + if( endIndex > t.getCharacterCount() ) + endIndex = t.getCharacterCount(); + string = t.string.substring( startIndex, endIndex ); + + int startingRun = t.charIndices[startIndex][0]; + int nRuns = 1 + t.charIndices[endIndex - 1][0] - startingRun; + runIndices = new int[ nRuns ][2]; + + runs = new GlyphVector[ nRuns ]; + for( int i = 0; i < nRuns; i++ ) + { + GlyphVector run = t.runs[ i + startingRun ]; + // Copy only the relevant parts of the first and last runs. + int beginGlyphIndex = (i > 0) ? 0 : t.charIndices[startIndex][1]; + int numEntries = ( i < nRuns - 1) ? run.getNumGlyphs() : + 1 + t.charIndices[endIndex - 1][1] - beginGlyphIndex; + + int[] codes = run.getGlyphCodes(beginGlyphIndex, numEntries, null); + runs[ i ] = font.createGlyphVector( frc, codes ); + runIndices[ i ][0] = t.runIndices[i + startingRun][0] - startIndex; + runIndices[ i ][1] = t.runIndices[i + startingRun][1] - startIndex; + } + runIndices[ nRuns - 1 ][1] = endIndex - 1; + + setCharIndices(); + determineWhiteSpace(); + } + + private void setCharIndices() + { + charIndices = new int[ getCharacterCount() ][2]; + int i = 0; + int currentChar = 0; + for(int run = 0; run < runs.length; run++) + { + currentChar = -1; + for( int gi = 0; gi < runs[ run ].getNumGlyphs(); gi++) + { + if( runs[ run ].getGlyphCharIndex( gi ) != currentChar ) + { + charIndices[ i ][0] = run; + charIndices[ i ][1] = gi; + currentChar = runs[ run ].getGlyphCharIndex( gi ); + i++; + } + } + } + } + + private static String getText(AttributedCharacterIterator iter) + { + StringBuffer sb = new StringBuffer(); + int idx = iter.getIndex(); + for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + sb.append(c); + iter.setIndex( idx ); + return sb.toString(); + } + + private static Font getFont(AttributedCharacterIterator iter) + { + Font f = (Font)iter.getAttribute(TextAttribute.FONT); + if( f == null ) + { + int size; + Float i = (Float)iter.getAttribute(TextAttribute.SIZE); + if( i != null ) + size = (int)i.floatValue(); + else + size = 14; + f = new Font("Dialog", Font.PLAIN, size ); + } + return f; } /** @@ -179,10 +275,14 @@ public final class TextLayout implements Cloneable gotDirection = true; break; } + determineWhiteSpace(); + } + private void determineWhiteSpace() + { // Determine if there's whitespace in the thing. // Ignore trailing chars. - i = string.length() - 1; + int i = string.length() - 1; hasWhitespace = false; while( i >= 0 && Character.isWhitespace( string.charAt(i) ) ) i--; @@ -251,56 +351,42 @@ public final class TextLayout implements Cloneable public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint) { - if( firstEndpoint < 0 || secondEndpoint > getCharacterCount() ) + if( secondEndpoint - firstEndpoint <= 0 ) + return new Rectangle2D.Float(); // Hmm? + + if( firstEndpoint < 0 || secondEndpoint > getCharacterCount()) return new Rectangle2D.Float(); GeneralPath gp = new GeneralPath(); - int i = 0; // run index - double advance = 0; - - // go to first run - while( runIndices[i + 1][1] < firstEndpoint ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - } + + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; - int j = 0; // index into the run. - if( runIndices[i][1] - runIndices[i][0] > 1 ) + double advance = 0; + + for( int i = 0; i < ri; i++ ) + advance += runs[i].getLogicalBounds().getWidth(); + + for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ ) { - while( runs[i].getGlyphCharIndex( j + 1 ) < - (firstEndpoint - runIndices[i][0] ) )j++; - } - - gp.append(runs[i].getGlyphVisualBounds( j ), false); - boolean keepGoing = true;; + int dg; + if( i == charIndices[ secondEndpoint - 1 ][0] ) + dg = charIndices[ secondEndpoint - 1][1]; + else + dg = runs[i].getNumGlyphs() - 1; - do - { - while( j < runs[i].getNumGlyphs() && - runs[i].getGlyphCharIndex( j ) + runIndices[i][0] < - secondEndpoint ) + for( int j = 0; j <= dg; j++ ) { Rectangle2D r2 = (runs[i].getGlyphVisualBounds( j )). getBounds2D(); Point2D p = runs[i].getGlyphPosition( j ); - r2.setRect( advance + p.getX(), r2.getY(), + r2.setRect( advance + r2.getX(), r2.getY(), r2.getWidth(), r2.getHeight() ); gp.append(r2, false); - j++; } - if( j >= runs[i].getNumGlyphs() ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - j = 0; - } - else - keepGoing = false; + advance += runs[i].getLogicalBounds().getWidth(); } - while( keepGoing ); - return gp; } @@ -384,55 +470,42 @@ public final class TextLayout implements Cloneable public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint, Rectangle2D bounds) { - if( firstEndpoint < 0 || secondEndpoint > getCharacterCount() ) + if( secondEndpoint - firstEndpoint <= 0 ) + return new Rectangle2D.Float(); // Hmm? + + if( firstEndpoint < 0 || secondEndpoint > getCharacterCount()) return new Rectangle2D.Float(); - int i = 0; // run index - double advance = 0; + Rectangle2D r = null; + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; - // go to first run - if( i > 0 ) - while( runIndices[i + 1][1] < firstEndpoint ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - } + double advance = 0; + + for( int i = 0; i < ri; i++ ) + advance += runs[i].getLogicalBounds().getWidth(); - int j = 0; // index into the run. - if( runIndices[i][1] - runIndices[i][0] > 1 ) + for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ ) { - while( runs[i].getGlyphCharIndex( j + 1 ) < - (firstEndpoint - runIndices[i][0] ) )j++; - } - - Rectangle2D r = (runs[i].getGlyphLogicalBounds( j )).getBounds2D(); - boolean keepGoing = true;; + int dg; // last index in this run to use. + if( i == charIndices[ secondEndpoint - 1 ][0] ) + dg = charIndices[ secondEndpoint - 1][1]; + else + dg = runs[i].getNumGlyphs() - 1; - do - { - while( j < runs[i].getNumGlyphs() && - runs[i].getGlyphCharIndex( j ) + runIndices[i][0] < - secondEndpoint ) + for(; gi <= dg; gi++ ) { - Rectangle2D r2 = (runs[i].getGlyphLogicalBounds( j )). + Rectangle2D r2 = (runs[i].getGlyphLogicalBounds( gi )). getBounds2D(); - Point2D p = runs[i].getGlyphPosition( j ); - r2.setRect( advance + p.getX(), r2.getY(), - r2.getWidth(), r2.getHeight() ); - r = r.createUnion( r2 ); - j++; + if( r == null ) + r = r2; + else + r = r.createUnion(r2); } + gi = 0; // reset glyph index into run for next run. - if( j >= runs[i].getNumGlyphs() ) - { - advance += runs[i].getLogicalBounds().getWidth(); - i++; - j = 0; - } - else - keepGoing = false; + advance += runs[i].getLogicalBounds().getWidth(); } - while( keepGoing ); return r; } diff --git a/java/awt/font/TextMeasurer.java b/java/awt/font/TextMeasurer.java index 18c286c57..e91c7ef16 100644 --- a/java/awt/font/TextMeasurer.java +++ b/java/awt/font/TextMeasurer.java @@ -1,5 +1,5 @@ /* TextMeasurer.java - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,67 +38,152 @@ exception statement from your version. */ package java.awt.font; -import gnu.classpath.NotImplementedException; - import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.awt.Shape; /** - * @author Michael Koch + * TextMeasurer is a small utility class for measuring the length of laid-out + * text objects. + * + * @author Sven de Marothy * @since 1.3 */ public final class TextMeasurer implements Cloneable { - private AttributedCharacterIterator ci; + private AttributedCharacterIterator text; private FontRenderContext frc; - + private TextLayout totalLayout; + private int numChars; + + /** + * Creates a TextMeasurer from a given text in the form of an + * <code>AttributedCharacterIterator</code> and a + * <code>FontRenderContext</code>. + */ public TextMeasurer (AttributedCharacterIterator text, FontRenderContext frc) { - this.ci = text; + this.text = text; this.frc = frc; + totalLayout = new TextLayout( text, frc ); + numChars = totalLayout.getCharacterCount(); } + /** + * Clones the TextMeasurer object + */ protected Object clone () { - try - { - return super.clone (); - } - catch (CloneNotSupportedException e) - { - // This may never occur - throw new InternalError (); - } + return new TextMeasurer( text, frc ); } + /** + * Update the text if a character is deleted at the position deletePos + * @param newParagraph - the updated paragraph. + * @param deletePos - the deletion position + */ public void deleteChar (AttributedCharacterIterator newParagraph, int deletePos) - throws NotImplementedException { - throw new Error ("not implemented"); + totalLayout = new TextLayout(newParagraph, frc); + if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() ) + throw new NullPointerException("Invalid deletePos:"+deletePos); + numChars = totalLayout.getCharacterCount(); + text = newParagraph; + } + + /** + * Update the text if a character is inserted at the position insertPos + * @param newParagraph - the updated paragraph. + * @param insertPos - the insertion position + */ + public void insertChar (AttributedCharacterIterator newParagraph, + int insertPos) + { + totalLayout = new TextLayout(newParagraph, frc); + if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() ) + throw new NullPointerException("Invalid insertPos:"+insertPos); + numChars = totalLayout.getCharacterCount(); + text = newParagraph; } + /*** + * Returns the total advance between two positions in the paragraph. + * Characters from start to limit-1 (inclusive) are included in this count. + * + * @param start - the starting character index. + * @param limit - the limiting index. + */ public float getAdvanceBetween (int start, int limit) - throws NotImplementedException { - throw new Error ("not implemented"); + Shape s = totalLayout.getLogicalHighlightShape( start, limit ); + return (float)s.getBounds2D().getWidth(); } + /** + * Returns a <code>TextLayout</code> object corresponding to the characters + * from text to limit. + * @param start - the starting character index. + * @param limit - the limiting index. + */ public TextLayout getLayout (int start, int limit) - throws NotImplementedException { - throw new Error ("not implemented"); + return new TextLayout( totalLayout, start, limit ); } + /** + * Returns the line-break index from a given starting index and a maximum + * advance. The index returned is the first character outside the given + * advance (or the limit of the string, if all remaining characters fit.) + * + * @param start - the starting index. + * @param maxAdvance - the maximum advance allowed. + * @return the index of the first character beyond maxAdvance, or the + * index of the last character + 1. + */ public int getLineBreakIndex (int start, float maxAdvance) - throws NotImplementedException - { - throw new Error ("not implemented"); - } + { + if( start < 0 ) + throw new IllegalArgumentException("Start parameter must be > 0."); + + double remainingLength = getAdvanceBetween( start, numChars ); + + int guessOffset = (int)( ( (double)maxAdvance / (double)remainingLength) + * ( (double)numChars - (double)start ) ); + guessOffset += start; + if( guessOffset > numChars ) + guessOffset = numChars; + + double guessLength = getAdvanceBetween( start, guessOffset ); + boolean makeSmaller = ( guessLength > maxAdvance ); + int inc = makeSmaller ? -1 : 1; + boolean keepGoing = true; + + do + { + guessOffset = guessOffset + inc; + if( guessOffset <= start || guessOffset > numChars ) + { + keepGoing = false; + } + else + { + guessLength = getAdvanceBetween( start, guessOffset ); + if( makeSmaller && ( guessLength <= maxAdvance) ) + keepGoing = false; + if( !makeSmaller && ( guessLength >= maxAdvance) ) + keepGoing = false; + } + } + while( keepGoing ); - public void insertChar (AttributedCharacterIterator newParagraph, - int insertPos) - throws NotImplementedException - { - throw new Error ("not implemented"); + // Return first index that doesn't fit. + if( !makeSmaller ) + guessOffset--; + + if( guessOffset > numChars ) + return numChars; + + return guessOffset; } } diff --git a/java/awt/image/BufferedImage.java b/java/awt/image/BufferedImage.java index e79a09a0f..6026e7898 100644 --- a/java/awt/image/BufferedImage.java +++ b/java/awt/image/BufferedImage.java @@ -504,7 +504,10 @@ public class BufferedImage extends Image int[] pixels = getRGB(x, y, width, height, (int[])null, offset, stride); - ColorModel model = getColorModel(); + // We already convert the color to RGB in the getRGB call, so + // we pass a simple RGB color model to the consumers. + ColorModel model = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, + 0xff000000); consumers.add(ic); diff --git a/java/lang/Thread.java b/java/lang/Thread.java index e039b4703..9a3e3a6f0 100644 --- a/java/lang/Thread.java +++ b/java/lang/Thread.java @@ -1254,4 +1254,19 @@ public class Thread implements Runnable private static final long serialVersionUID = 605505746047245783L; } + + /** + * Returns the current state of the thread. This + * is designed for monitoring thread behaviour, rather + * than for synchronization control. + * + * @return the current thread state. + */ + public State getState() + { + VMThread t = vmThread; + return t == null ? null : State.valueOf(t.getState()); + } + + } diff --git a/java/lang/management/ClassLoadingMXBean.java b/java/lang/management/ClassLoadingMXBean.java new file mode 100644 index 000000000..2a8651b9c --- /dev/null +++ b/java/lang/management/ClassLoadingMXBean.java @@ -0,0 +1,103 @@ +/* ClassLoadingMXBean.java - Interface for a class loading bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.management; + +/** + * Provides access to information about the class loading + * behaviour of the current invocation of the virtual + * machine. An instance of this bean is obtained by calling + * {@link ManagementFactory#getClassLoadingMXBean()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface ClassLoadingMXBean +{ + + /** + * Returns the number of classes currently loaded by + * the virtual machine. + * + * @return the number of loaded classes. + */ + int getLoadedClassCount(); + + /** + * Returns the total number of classes loaded by the + * virtual machine since it was started. This is the + * sum of the currently loaded classes and those that + * have been unloaded. + * + * @return the total number of classes that have been + * loaded by the virtual machine since it started. + */ + long getTotalLoadedClassCount(); + + /** + * Returns the number of classes that have been unloaded + * by the virtual machine since it was started. + * + * @return the number of unloaded classes. + */ + long getUnloadedClassCount(); + + /** + * Returns true if the virtual machine will emit additional + * information when classes are loaded and unloaded. The + * format of the output is left up to the virtual machine. + * + * @return true if verbose class loading output is on. + */ + boolean isVerbose(); + + /** + * Turns on or off the emission of additional information + * when classes are loaded and unloaded. The format of the + * output is left up to the virtual machine. This method + * may be called by multiple threads concurrently, but there + * is only one global setting of verbosity that is affected. + * + * @param verbose the new setting for verbose class loading + * output. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("control"). + */ + void setVerbose(boolean verbose); + +} + diff --git a/java/lang/management/ManagementFactory.java b/java/lang/management/ManagementFactory.java index b3db1b96d..5f99bbe1d 100644 --- a/java/lang/management/ManagementFactory.java +++ b/java/lang/management/ManagementFactory.java @@ -37,6 +37,9 @@ exception statement from your version. */ package java.lang.management; +import gnu.classpath.NotImplementedException; + +import gnu.java.lang.management.ClassLoadingMXBeanImpl; import gnu.java.lang.management.OperatingSystemMXBeanImpl; import gnu.java.lang.management.RuntimeMXBeanImpl; @@ -71,6 +74,11 @@ public class ManagementFactory private static RuntimeMXBean runtimeBean; /** + * The class loading management bean. + */ + private static ClassLoadingMXBean classLoadingBean; + + /** * Private constructor to prevent instance creation. */ private ManagementFactory() {} @@ -103,4 +111,31 @@ public class ManagementFactory return runtimeBean; } + /** + * Returns the class loading management bean for the + * running virtual machine. + * + * @return an instance of {@link ClassLoadingMXBean} for + * this virtual machine. + */ + public static ClassLoadingMXBean getClassLoadingMXBean() + { + if (classLoadingBean == null) + classLoadingBean = new ClassLoadingMXBeanImpl(); + return classLoadingBean; + } + + /** + * Returns the thread management bean for the running + * virtual machine. + * + * @return an instance of {@link ThreadMXBean} for + * this virtual machine. + */ + public static ThreadMXBean getThreadMXBean() + throws NotImplementedException + { + return null; + } + } diff --git a/java/lang/management/OperatingSystemMXBean.java b/java/lang/management/OperatingSystemMXBean.java index 74b9ae5a1..2430a9fbf 100644 --- a/java/lang/management/OperatingSystemMXBean.java +++ b/java/lang/management/OperatingSystemMXBean.java @@ -39,7 +39,7 @@ package java.lang.management; /** * Provides access to information about the underlying operating - * system. Instances of this bean are obtained by calling + * system. An instance of this bean is obtained by calling * {@link ManagementFactory#getOperatingSystemMXBean()}. * * @author Andrew John Hughes (gnu_andrew@member.fsf.org) diff --git a/java/lang/management/RuntimeMXBean.java b/java/lang/management/RuntimeMXBean.java index 59b6d0eb1..a2931d127 100644 --- a/java/lang/management/RuntimeMXBean.java +++ b/java/lang/management/RuntimeMXBean.java @@ -42,7 +42,7 @@ import java.util.Map; /** * Provides access to information about the underlying virtual - * machine. Instances of this bean are obtained by calling + * machine. An instance of this bean is obtained by calling * {@link ManagementFactory#getRuntimeMXBean()}. * * @author Andrew John Hughes (gnu_andrew@member.fsf.org) diff --git a/java/lang/management/ThreadInfo.java b/java/lang/management/ThreadInfo.java new file mode 100644 index 000000000..53c6651ee --- /dev/null +++ b/java/lang/management/ThreadInfo.java @@ -0,0 +1,405 @@ +/* ThreadInfo.java - Information on a thread + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.management; + +/** + * <p> + * A class which maintains information about a particular + * thread. This information includes: + * </p> + * <ul> + * <li><strong>General Thread Information:</strong> + * <ul> + * <li>The identifier of the thread.</li> + * <li>The name of the thread.</li> + * </ul> + * </li> + * <li><strong>Execution Information:</strong> + * <ul> + * <li>The current state of the thread (e.g. blocked, runnable)</li> + * <li>The object upon which the thread is blocked, either because + * the thread is waiting to obtain the monitor of that object to enter + * one of its synchronized monitor, or because + * {@link java.lang.Object#wait()} has been called while the thread + * was within a method of that object.</li> + * <li>The thread identifier of the current thread holding an object's + * monitor, upon which the thread described here is blocked.</li> + * <li>The stack trace of the thread (if requested on creation + * of this object</li> + * </ul> + * <li><strong>Synchronization Statistics</strong> + * <ul> + * <li>The number of times the thread has been blocked waiting for + * an object's monitor or in a {@link java.lang.Object#wait()} call.</li> + * <li>The accumulated time the thread has been blocked waiting for + * an object's monitor on in a {@link java.lang.Object#wait()} call. + * The availability of these statistics depends on the virtual machine's + * support for thread contention monitoring (see + * {@link ThreadMXBean#isThreadContentionMonitoringSupported()}.</li> + * </ul> + * </li> + * </ul> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + * @see ThreadMXBean#isThreadContentionMonitoringSupported() + */ +public class ThreadInfo +{ + + /** + * The thread which this instance concerns. + */ + private Thread thread; + + /** + * The maximum depth of the stack traces for this thread. + */ + private int maxDepth; + + /** + * Cache a local reference to the thread management bean. + */ + private static ThreadMXBean bean = null; + + /** + * Constructs a new {@link ThreadInfo} corresponding + * to the thread specified. + * + * @param thread the thread on which the new instance + * will be based. + */ + ThreadInfo(Thread thread, int maxDepth) + { + this.thread = thread; + this.maxDepth = maxDepth; + } + + /** + * Returns the number of times this thread has been + * in the {@link java.lang.Thread.State#BLOCKED} state. + * A thread enters this state when it is waiting to + * obtain an object's monitor. This may occur either + * on entering a synchronized method for the first time, + * or on re-entering it following a call to + * {@link java.lang.Object#wait()}. + * + * @return the number of times this thread has been blocked. + */ + public long getBlockedCount() + { + return VMThreadInfo.getBlockedCount(thread); + } + + /** + * <p> + * Returns the accumulated number of milliseconds this + * thread has been in the + * {@link java.lang.Thread.State#BLOCKED} state + * since thread contention monitoring was last enabled. + * A thread enters this state when it is waiting to + * obtain an object's monitor. This may occur either + * on entering a synchronized method for the first time, + * or on re-entering it following a call to + * {@link java.lang.Object#wait()}. + * </p> + * <p> + * Use of this method requires virtual machine support + * for thread contention monitoring and for this support + * to be enabled. + * </p> + * + * @return the accumulated time (in milliseconds) that this + * thread has spent in the blocked state, since + * thread contention monitoring was enabled, or -1 + * if thread contention monitoring is disabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support contention + * monitoring. + * @see ThreadMXBean#isThreadContentionMonitoringEnabled() + * @see ThreadMXBean#isThreadContentionMonitoringSupported() + */ + public long getBlockedTime() + { + if (bean == null) + bean = ManagementFactory.getThreadMXBean(); + // Will throw UnsupportedOperationException for us + if (bean.isThreadContentionMonitoringEnabled()) + return VMThreadInfo.getBlockedTime(thread); + else + return -1; + } + + /** + * <p> + * Returns a {@link java.lang.String} representation of + * the monitor lock on which this thread is blocked. If + * the thread is not blocked, this method returns + * <code>null</code>. + * </p> + * <p> + * The returned {@link java.lang.String} is constructed + * using the class name and identity hashcode (usually + * the memory address of the object) of the lock. The + * two are separated by the '@' character, and the identity + * hashcode is represented in hexadecimal. Thus, for a + * lock, <code>l</code>, the returned value is + * the result of concatenating + * <code>l.getClass().getName()</code>, <code>"@"</code> + * and + * <code>Integer.toHexString(System.identityHashCode(l))</code>. + * The value is only unique to the extent that the identity + * hash code is also unique. + * </p> + * + * @return a string representing the lock on which this + * thread is blocked, or <code>null</code> if + * the thread is not blocked. + */ + public String getLockName() + { + if (thread.getState() == Thread.State.BLOCKED) + return null; + Object lock = VMThreadInfo.getLock(thread); + return lock.getClass().getName() + "@" + + Integer.toHexString(System.identityHashCode(lock)); + } + + /** + * Returns the identifier of the thread which owns the + * monitor lock this thread is waiting for. -1 is returned + * if either this thread is not blocked, or the lock is + * not held by any other thread. + * + * @return the thread identifier of thread holding the lock + * this thread is waiting for, or -1 if the thread + * is not blocked or the lock is not held by another + * thread. + */ + public long getLockOwnerId() + { + if (thread.getState() == Thread.State.BLOCKED) + return -1; + Thread lockOwner = VMThreadInfo.getLockOwner(thread); + if (lockOwner == null) + return -1; + return lockOwner.getId(); + } + + /** + * Returns the name of the thread which owns the + * monitor lock this thread is waiting for. <code>null</code> + * is returned if either this thread is not blocked, + * or the lock is not held by any other thread. + * + * @return the thread identifier of thread holding the lock + * this thread is waiting for, or <code>null</code> + * if the thread is not blocked or the lock is not + * held by another thread. + */ + public String getLockOwnerName() + { + if (thread.getState() == Thread.State.BLOCKED) + return null; + Thread lockOwner = VMThreadInfo.getLockOwner(thread); + if (lockOwner == null) + return null; + return lockOwner.getName(); + } + + /** + * <p> + * Returns the stack trace of this thread to the depth + * specified on creation of this {@link ThreadInfo} + * object. If the depth is zero, an empty array will + * be returned. For non-zero arrays, the elements + * start with the most recent trace at position zero. + * The bottom of the stack represents the oldest method + * invocation which meets the depth requirements. + * </p> + * <p> + * Some virtual machines may not be able to return + * stack trace information for a thread. In these + * cases, an empty array will also be returned. + * </p> + * + * @return an array of {@link java.lang.StackTraceElement}s + * representing the trace of this thread. + */ + public StackTraceElement[] getStackTrace() + { + if (maxDepth == 0) + return new StackTraceElement[0]; + return VMThreadInfo.getStackTrace(thread, maxDepth); + } + + /** + * Returns the identifier of the thread associated with + * this instance of {@link ThreadInfo}. + * + * @return the thread's identifier. + */ + public long getThreadId() + { + return thread.getId(); + } + + /** + * Returns the name of the thread associated with + * this instance of {@link ThreadInfo}. + * + * @return the thread's name. + */ + public String getThreadName() + { + return thread.getName(); + } + + /** + * Returns the state of the thread associated with + * this instance of {@link ThreadInfo}. + * + * @return the thread's state. + */ + public Thread.State getThreadState() + { + return thread.getState(); + } + + /** + * Returns the number of times this thread has been + * in the {@link java.lang.Thread.State#WAITING} + * or {@link java.lang.Thread.State#TIMED_WAITING} state. + * A thread enters one of these states when it is waiting + * due to a call to {@link java.lang.Object.wait()}, + * {@link java.lang.Object.join()} or + * {@link java.lang.concurrent.locks.LockSupport.park()}, + * either with an infinite or timed delay, respectively. + * + * @return the number of times this thread has been waiting. + */ + public long getWaitedCount() + { + return VMThreadInfo.getWaitedCount(thread); + } + + /** + * <p> + * Returns the accumulated number of milliseconds this + * thread has been in the + * {@link java.lang.Thread.State#WAITING} or + * {@link java.lang.Thread.State#TIMED_WAITING} state, + * since thread contention monitoring was last enabled. + * A thread enters one of these states when it is waiting + * due to a call to {@link java.lang.Object.wait()}, + * {@link java.lang.Object.join()} or + * {@link java.lang.concurrent.locks.LockSupport.park()}, + * either with an infinite or timed delay, respectively. + * </p> + * <p> + * Use of this method requires virtual machine support + * for thread contention monitoring and for this support + * to be enabled. + * </p> + * + * @return the accumulated time (in milliseconds) that this + * thread has spent in one of the waiting states, since + * thread contention monitoring was enabled, or -1 + * if thread contention monitoring is disabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support contention + * monitoring. + * @see ThreadMXBean#isThreadContentionMonitoringEnabled() + * @see ThreadMXBean#isThreadContentionMonitoringSupported() + */ + public long getWaitedTime() + { + if (bean == null) + bean = ManagementFactory.getThreadMXBean(); + // Will throw UnsupportedOperationException for us + if (bean.isThreadContentionMonitoringEnabled()) + return VMThreadInfo.getWaitedTime(thread); + else + return -1; + } + + /** + * Returns true if the thread is in a native method. This + * excludes native code which forms part of the virtual + * machine itself, or which results from Just-In-Time + * compilation. + * + * @return true if the thread is in a native method, false + * otherwise. + */ + public boolean isInNative() + { + return VMThreadInfo.isInNative(thread); + } + + /** + * Returns true if the thread has been suspended using + * {@link java.lang.Thread#suspend()}. + * + * @return true if the thread is suspended, false otherwise. + */ + public boolean isSuspended() + { + return VMThreadInfo.isSuspended(thread); + } + + /** + * Returns a {@link java.lang.String} representation of + * this {@link ThreadInfo} object. This takes the form + * <code>java.lang.ThreadInfo[id=tid, maxDepth=md]</code>, + * where <code>tid</code> is the thread identifier + * and <code>md</code> is the maximum depth used by + * this {@link ThreadInfo}. + * + * @return the string specified above. + */ + public String toString() + { + return getClass().getName() + + "[id=" + thread.getId() + ", maxDepth=" + + maxDepth + "]"; + } + +} diff --git a/java/lang/management/ThreadMXBean.java b/java/lang/management/ThreadMXBean.java new file mode 100644 index 000000000..2926548ad --- /dev/null +++ b/java/lang/management/ThreadMXBean.java @@ -0,0 +1,497 @@ +/* ThreadMXBean.java - Interface for a thread bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.management; + +/** + * <p> + * Provides access to information about the threads + * of the virtual machine. An instance of this bean is + * obtained by calling + * {@link ManagementFactory#getThreadMXBean()}. + * </p> + * <p> + * Each thread within the virtual machine is given an + * identifier, which is guaranteed to be unique to a + * particular thread over its lifetime (after which it + * may be reused). The identifier for a thread may be + * obtained by calling {@link java.lang.Thread#getId()}. + * This identifier is used within implementations of this + * interface to obtain information about a particular thread + * (or series of threads, in the case of an array of identifiers). + * </p> + * <p> + * This bean supports some optional behaviour, which all + * virtual machines may not choose to implement. Specifically, + * this includes the monitoring of the CPU time used by a + * thread, and the monitoring of thread contention. The former + * is further subdivided into the monitoring of either just + * the current thread or all threads. The methods + * {@link #isThreadCpuTimeSupported()}, + * {@link #isCurrentThreadCpuTimeSupported()} and + * {@link #isThreadContentionMonitoringSupported()} may be + * used to determine whether or not this functionality is + * supported. + * </p> + * <p> + * Furthermore, both these facilities may be disabled. + * In fact, thread contention monitoring is disabled by + * default, and must be explictly turned on by calling + * the {@link #setThreadContentionMonitoringEnabled(boolean)} + * method. + * </p> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface ThreadMXBean +{ + + /** + * <p> + * This method obtains a list of threads which are deadlocked + * waiting to obtain monitor ownership. On entering a synchronized + * method of an object, or re-entering it after returning from an + * {@link java.lang.Object#wait()} call, a thread obtains ownership + * of the object's monitor. + * </p> + * <p> + * Deadlocks can occur in this situation if one or more threads end up + * waiting for a monitor, P, while also retaining ownership of a monitor, + * Q, required by the thread that currently owns P. To give a simple + * example, imagine thread A calls a synchronized method, R, obtaining the + * monitor, P. It then sleeps within that method, allowing thread B + * to run, but still retaining ownership of P. B calls another + * synchronized method, S, which causes it to obtain the monitor, Q, + * of a different object. While in that method, it then wants to + * call the original synchronized method, R, called by A. Doing so + * requires ownership of P, which is still held by A. Hence, it + * becomes blocked. + * </p> + * <p> + * A then finishes its sleep, becomes runnable, and is then allowed + * to run, being the only eligible thread in this scenario. A tries + * to call the synchronized method, S. It also gets blocked, because + * B still holds the monitor, Q. Hence, the two threads, A and B, + * are deadlocked, as neither can give up its monitor without first + * obtaining the monitor held by the other thread. + * </p> + * <p> + * Calling this method in this scenario would return the thread IDs + * of A and B. Note that this method is not designed for controlling + * synchronization, but for troubleshooting problems which cause such + * deadlocks; it may be prohibitively expensive to use in normal + * operation. + * </p> + * + * @return an array of thread identifiers, corresponding to threads + * which are currently in a deadlocked situation. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("monitor"). + */ + long[] findMonitorDeadlockedThreads(); + + /** + * Returns all live thread identifiers at the time of initial + * execution. Some thread identifiers in the returned array + * may refer to terminated threads, if this occurs during the + * lifetime of this method. + * + * @return an array of thread identifiers, corresponding to + * current live threads. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("monitor"). + */ + long[] getAllThreadIds(); + + /** + * <p> + * Returns the total number of nanoseconds of CPU time + * the current thread has used. This is equivalent to calling + * <code>{@link #getThreadCpuTime()}(Thread.currentThread.getId())</code>. + * </p> + * <p> + * Note that the value is only nanosecond-precise, and not accurate; there + * is no guarantee that the difference between two values is really a + * nanosecond. Also, the value is prone to overflow if the offset + * exceeds 2^63. The use of this method depends on virtual machine + * support for measurement of the CPU time of the current thread, + * and on this functionality being enabled. + * </p> + * + * @return the total number of nanoseconds of CPU time the current + * thread has used, or -1 if CPU time monitoring is disabled. + * @throws UnsupportedOperationException if CPU time monitoring is not + * supported. + * @see #getCurrentThreadUserTime() + * @see #isCurrentThreadCpuTimeSupported() + * @see #isThreadCpuTimeEnabled() + * @see #setThreadCpuTimeEnabled(boolean) + */ + long getCurrentThreadCpuTime(); + + /** + * <p> + * Returns the total number of nanoseconds of CPU time + * the current thread has executed in user mode. This is + * equivalent to calling + * <code>{@link #getThreadUserTime()}(Thread.currentThread.getId())</code>. + * </p> + * <p> + * Note that the value is only nanosecond-precise, and not accurate; there + * is no guarantee that the difference between two values is really a + * nanosecond. Also, the value is prone to overflow if the offset + * exceeds 2^63. The use of this method depends on virtual machine + * support for measurement of the CPU time of the current thread, + * and on this functionality being enabled. + * </p> + * + * @return the total number of nanoseconds of CPU time the current + * thread has executed in user mode, or -1 if CPU time + * monitoring is disabled. + * @throws UnsupportedOperationException if CPU time monitoring is not + * supported. + * @see #getCurrentThreadCpuTime() + * @see #isCurrentThreadCpuTimeSupported() + * @see #isThreadCpuTimeEnabled() + * @see #setThreadCpuTimeEnabled(boolean) + */ + long getCurrentThreadUserTime(); + + /** + * Returns the number of live daemon threads. + * + * @return the number of live daemon threads. + */ + int getDaemonThreadCount(); + + /** + * Returns the peak number of live threads since + * the virtual machine was started or the count + * reset using {@link #resetPeakThreadCount()}. + * + * @return the peak live thread count. + * @see #resetPeakThreadCount() + */ + int getPeakThreadCount(); + + /** + * Returns the number of live threads, including + * both daemon threads and non-daemon threads. + * + * @return the current number of live threads. + */ + int getThreadCount(); + + /** + * <p> + * Returns the total number of nanoseconds of CPU time + * the specified thread has used. + * </p> + * <p> + * Note that the value is only nanosecond-precise, and not accurate; there + * is no guarantee that the difference between two values is really a + * nanosecond. Also, the value is prone to overflow if the offset + * exceeds 2^63. The use of this method depends on virtual machine + * support for measurement of the CPU time of the current thread, + * and on this functionality being enabled. + * </p> + * + * @param id the thread identifier of the thread whose CPU time is being + * monitored. + * @return the total number of nanoseconds of CPU time the specified + * thread has used, or -1 if CPU time monitoring is disabled. + * @throws IllegalArgumentException if <code>id</code> <= 0. + * @throws UnsupportedOperationException if CPU time monitoring is not + * supported. + * @see #getThreadUserTime(long) + * @see #isThreadCpuTimeSupported() + * @see #isThreadCpuTimeEnabled() + * @see #setThreadCpuTimeEnabled(boolean) + */ + long getThreadCpuTime(long id); + + /** + * Returns information on the specified thread without any + * stack trace information. This is equivalent to + * <code>{@link #getThreadInfo}(id, 0)</code>. If the + * identifier specifies a thread which is either non-existant + * or not alive, then the method returns <code>null</code>. + * + * @param id the identifier of the thread to return information + * on. + * @return a {@link ThreadInfo} object pertaining to the specified + * thread, or <code>null</code> if the identifier specifies + * a thread that doesn't exist or is not alive. + * @throws IllegalArgumentException if <code>id</code> <= 0. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("monitor"). + */ + ThreadInfo getThreadInfo(long id); + + /** + * Returns information on the specified threads without any + * stack trace information. This is equivalent to + * <code>{@link #getThreadInfo}(ids, 0)</code>. If an + * identifier specifies a thread which is either non-existant + * or not alive, then the corresponding element in the returned + * array is <code>null</code>. + * + * @param ids an array of thread identifiers to return information + * on. + * @return an array of {@link ThreadInfo} objects matching the + * specified threads. The corresponding element is + * <code>null</code> if the identifier specifies + * a thread that doesn't exist or is not alive. + * @throws IllegalArgumentException if an identifier in the array is + * <= 0. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("monitor"). + */ + ThreadInfo[] getThreadInfo(long[] ids); + + /** + * Returns information on the specified thread with + * stack trace information to the supplied depth. If the + * identifier specifies a thread which is either non-existant + * or not alive, then the method returns <code>null</code>. + * A maximum depth of 0 corresponds to an empty stack trace + * (an empty array is returned by the appropriate + * {@link ThreadInfo} method). A maximum depth of + * <code>Integer.MAX_VALUE</code> returns the full stack trace. + * + * @param id the identifier of the thread to return information + * on. + * @param maxDepth the maximum depth of the stack trace. + * Values of 0 or <code>Integer.MAX_VALUE</code> + * correspond to an empty and full stack trace + * respectively. + * @return a {@link ThreadInfo} object pertaining to the specified + * thread, or <code>null</code> if the identifier specifies + * a thread that doesn't exist or is not alive. + * @throws IllegalArgumentException if <code>id</code> <= 0. + * @throws IllegalArgumentException if <code>maxDepth</code> <= 0. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("monitor"). + */ + ThreadInfo getThreadInfo(long id, int maxDepth); + + /** + * Returns information on the specified threads with + * stack trace information to the supplied depth. If an + * identifier specifies a thread which is either non-existant + * or not alive, then the corresponding element in the returned + * array is <code>null</code>. A maximum depth of 0 corresponds + * to an empty stack trace (an empty array is returned by the + * appropriate {@link ThreadInfo} method). A maximum depth of + * <code>Integer.MAX_VALUE</code> returns the full stack trace. + * + * @param ids an array of thread identifiers to return information + * on. + * @param maxDepth the maximum depth of the stack trace. + * Values of 0 or <code>Integer.MAX_VALUE</code> + * correspond to an empty and full stack trace + * respectively. + * @return an array of {@link ThreadInfo} objects matching the + * specified threads. The corresponding element is + * <code>null</code> if the identifier specifies + * a thread that doesn't exist or is not alive. + * @throws IllegalArgumentException if an identifier in the array is + * <= 0. + * @throws IllegalArgumentException if <code>maxDepth</code> <= 0. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("monitor"). + */ + ThreadInfo[] getThreadInfo(long[] ids, int maxDepth); + + /** + * <p> + * Returns the total number of nanoseconds of CPU time + * the specified thread has executed in user mode. + * </p> + * <p> + * Note that the value is only nanosecond-precise, and not accurate; there + * is no guarantee that the difference between two values is really a + * nanosecond. Also, the value is prone to overflow if the offset + * exceeds 2^63. The use of this method depends on virtual machine + * support for measurement of the CPU time of the current thread, + * and on this functionality being enabled. + * </p> + * + * @param id the thread identifier of the thread whose CPU time is being + * monitored. + * @return the total number of nanoseconds of CPU time the specified + * thread has executed in user mode, or -1 if CPU time monitoring + * is disabled. + * @throws IllegalArgumentException if <code>id</code> <= 0. + * @throws UnsupportedOperationException if CPU time monitoring is not + * supported. + * @see #getThreadCpuTime(long) + * @see #isThreadCpuTimeSupported() + * @see #isThreadCpuTimeEnabled() + * @see #setThreadCpuTimeEnabled(boolean) + */ + long getThreadUserTime(long id); + + /** + * Returns the total number of threads that have been + * created and started during the lifetime of the virtual + * machine. + * + * @return the total number of started threads. + */ + long getTotalStartedThreadCount(); + + /** + * Returns true if the virtual machine supports the monitoring + * of the CPU time used by the current thread. This is implied + * by {@link isThreadCpuTimeSupported()} returning true. + * + * @return true if monitoring of the CPU time used by the current + * thread is supported by the virtual machine. + * @see #isThreadCpuTimeEnabled() + * @see #isThreadCpuTimeSupported() + * @see #setThreadCpuTimeEnabled(boolean) + */ + boolean isCurrentThreadCpuTimeSupported(); + + /** + * Returns true if thread contention monitoring is currently + * enabled. + * + * @return true if thread contention monitoring is enabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support contention + * monitoring. + * @see #isThreadContentionMonitoringSupported() + * @see #setThreadContentionMonitoringEnabled(boolean) + */ + boolean isThreadContentionMonitoringEnabled(); + + /** + * Returns true if thread contention monitoring is supported + * by the virtual machine. + * + * @return true if thread contention monitoring is supported + * by the virtual machine. + * @see #isThreadContentionMonitoringEnabled() + * @see #setThreadContentionMonitoringEnabled(boolean) + */ + boolean isThreadContentionMonitoringSupported(); + + /** + * Returns true if monitoring of the CPU time used by a thread + * is currently enabled. + * + * @return true if thread CPU time monitoring is enabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support CPU time + * monitoring. + * @see #isCurrentThreadCpuTimeSupported() + * @see #isThreadCpuTimeSupported() + * @see #setThreadCpuTimeEnabled(boolean) + */ + boolean isThreadCpuTimeEnabled(); + + /** + * Returns true if the virtual machine supports the monitoring + * of the CPU time used by all threads. This implies + * that {@link isCurrentThreadCpuTimeSupported()} returns true. + * + * @return true if monitoring of the CPU time used by the current + * thread is supported by the virtual machine. + * @see #isCurrentThreadCpuTimeSupported() + * @see #isThreadCpuTimeEnabled() + * @see #setThreadCpuTimeEnabled(boolean) + */ + boolean isThreadCpuTimeSupported(); + + /** + * Resets the peak live thread count to the + * current number of live threads, as returned + * by {@link #getThreadCount()}. + * + * @see #getPeakThreadCount() + * @see #getThreadCount() + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("control"). + */ + void resetPeakThreadCount(); + + /** + * Toggles the monitoring of thread contention. Thread + * contention monitoring is disabled by default. Each + * time contention monitoring is re-enabled, the times + * it maintains are reset. + * + * @param enable true if monitoring should be enabled, + * false if it should be disabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support contention + * monitoring. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("control"). + * @see #isThreadContentionMonitoringEnabled() + * @see #isThreadContentionMonitoringSupported() + */ + void setThreadContentionMonitoringEnabled(boolean enable); + + /** + * Toggles the monitoring of CPU time used by threads. The + * initial setting is dependent on the underlying virtual + * machine. On enabling CPU time monitoring, the virtual + * machine may take any value up to and including the current + * time as the start time for monitoring. + * + * @param enable true if monitoring should be enabled, + * false if it should be disabled. + * @throws UnsupportedOperationException if the virtual + * machine does not + * support CPU time + * monitoring. + * @throws SecurityException if a security manager exists and + * denies ManagementPermission("control"). + * @see #isCurrentThreadCpuTimeSupported() + * @see #isThreadCpuTimeEnabled() + * @see #isThreadCpuTimeSupported() + */ + void setThreadCpuTimeEnabled(boolean enable); + +} diff --git a/java/net/URL.java b/java/net/URL.java index 967cc80f6..85037b3e7 100644 --- a/java/net/URL.java +++ b/java/net/URL.java @@ -482,7 +482,17 @@ public final class URL implements Serializable } catch (URLParseError e) { - throw new MalformedURLException(e.getMessage()); + MalformedURLException mue = new MalformedURLException(e.getMessage()); + mue.initCause(e); + throw mue; + } + catch (RuntimeException e) + { + // This isn't documented, but the JDK also catches + // RuntimeExceptions here. + MalformedURLException mue = new MalformedURLException(e.getMessage()); + mue.initCause(e); + throw mue; } if (hashAt >= 0) diff --git a/java/rmi/server/UID.java b/java/rmi/server/UID.java index 359630422..940339e81 100644 --- a/java/rmi/server/UID.java +++ b/java/rmi/server/UID.java @@ -94,23 +94,23 @@ public final class UID * The time stamp, when the UID was created. */ private long time; - + /** * Create the new UID that would have the described features of the * uniqueness. */ public UID() { - time = System.currentTimeMillis(); - unique = machineId; - if (time > last) - { - last = time; - count = uidCounter = Short.MIN_VALUE; - } - else + synchronized (UID.class) { - synchronized (UID.class) + time = System.currentTimeMillis(); + unique = machineId; + if (time > last) + { + last = time; + count = uidCounter = Short.MIN_VALUE; + } + else { if (uidCounter == Short.MAX_VALUE) { @@ -126,8 +126,7 @@ public final class UID uidCounter = Short.MIN_VALUE; time = last = System.currentTimeMillis(); } - - count = uidCounter++; + count = ++uidCounter; } } } @@ -210,7 +209,7 @@ public final class UID ^ hostIpHash; } - /** + /** * Get the string representation of this UID. * * @return a string, uniquely identifying this id. @@ -219,9 +218,8 @@ public final class UID { int max = Character.MAX_RADIX; // Translate into object count, counting from 0. - long lc = (count + Short.MIN_VALUE) & 0xFFFF; - return Long.toString(time, max) + ":" - + Long.toString(unique, max) + ":" + long lc = (count - Short.MIN_VALUE) & 0xFFFF; + return Long.toString(unique, max) + ":" + Long.toString(time, max) + "." + Long.toString(lc, max); } } diff --git a/java/security/cert/X509CertSelector.java b/java/security/cert/X509CertSelector.java index 205f4bcf7..154ed2e4d 100644 --- a/java/security/cert/X509CertSelector.java +++ b/java/security/cert/X509CertSelector.java @@ -696,7 +696,7 @@ public class X509CertSelector implements CertSelector, Cloneable if (altNames == null) altNames = new LinkedList(); ArrayList l = new ArrayList(2); - l.add(new Integer(id)); + l.add(Integer.valueOf(id)); l.add(name); altNames.add(l); } @@ -715,7 +715,7 @@ public class X509CertSelector implements CertSelector, Cloneable if (altNames == null) altNames = new LinkedList(); ArrayList l = new ArrayList(2); - l.add(new Integer(id)); + l.add(Integer.valueOf(id)); l.add(name); altNames.add(l); } diff --git a/java/text/AttributedString.java b/java/text/AttributedString.java index 8528551a8..c220f6025 100644 --- a/java/text/AttributedString.java +++ b/java/text/AttributedString.java @@ -223,16 +223,13 @@ public class AttributedString // If the attribute run starts before the beginning index, we // need to junk it if it is an Annotation. Object attrib_obj = aci.getAttribute(attrib); - if (rs < begin) + rs -= begin; + if (rs < 0) { if (attrib_obj instanceof Annotation) continue; - rs = begin; - } - else - { - rs -= begin; + rs = 0; } // Create a map object. Yes this will only contain one attribute @@ -245,7 +242,7 @@ public class AttributedString c = aci.next(); } - while(c != CharacterIterator.DONE); + while( aci.getIndex() < end ); attribs = new AttributeRange[accum.size()]; attribs = (AttributeRange[]) accum.toArray(attribs); diff --git a/java/util/logging/LogManager.java b/java/util/logging/LogManager.java index ae0f446a8..444ab6a26 100644 --- a/java/util/logging/LogManager.java +++ b/java/util/logging/LogManager.java @@ -39,6 +39,8 @@ exception statement from your version. */ package java.util.logging; +import gnu.classpath.SystemProperties; + import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.ByteArrayInputStream; @@ -50,12 +52,11 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; -import gnu.classpath.SystemProperties; - /** * The <code>LogManager</code> maintains a hierarchical namespace * of Logger objects and manages properties for configuring the logging @@ -108,11 +109,23 @@ import gnu.classpath.SystemProperties; public class LogManager { /** + * The object name for the logging management bean. + * @since 1.5 + */ + public static final String LOGGING_MXBEAN_NAME + = "java.util.logging:type=Logging"; + + /** * The singleton LogManager instance. */ private static LogManager logManager; /** + * The singleton logging bean. + */ + private static LoggingMXBean loggingBean; + + /** * The registered named loggers; maps the name of a Logger to * a WeakReference to it. */ @@ -902,4 +915,63 @@ public class LogManager } } + /** + * Return the logging bean. There is a single logging bean per + * VM instance. + * @since 1.5 + */ + public static synchronized LoggingMXBean getLoggingMXBean() + { + if (loggingBean == null) + { + loggingBean = new LoggingMXBean() + { + public String getLoggerLevel(String logger) + { + LogManager mgr = getLogManager(); + Logger l = mgr.getLogger(logger); + if (l == null) + return null; + Level lev = l.getLevel(); + if (lev == null) + return ""; + return lev.getName(); + } + + public List getLoggerNames() + { + LogManager mgr = getLogManager(); + // This is inefficient, but perhaps better for maintenance. + return Collections.list(mgr.getLoggerNames()); + } + + public String getParentLoggerName(String logger) + { + LogManager mgr = getLogManager(); + Logger l = mgr.getLogger(logger); + if (l == null) + return null; + l = l.getParent(); + if (l == null) + return ""; + return l.getName(); + } + + public void setLoggerLevel(String logger, String level) + { + LogManager mgr = getLogManager(); + Logger l = mgr.getLogger(logger); + if (l == null) + throw new IllegalArgumentException("no logger named " + logger); + Level newLevel; + if (level == null) + newLevel = null; + else + newLevel = Level.parse(level); + l.setLevel(newLevel); + } + }; + } + return loggingBean; + } } diff --git a/java/util/logging/LoggingMXBean.java b/java/util/logging/LoggingMXBean.java new file mode 100644 index 000000000..5f866c980 --- /dev/null +++ b/java/util/logging/LoggingMXBean.java @@ -0,0 +1,85 @@ +/* LoggingMxBean.java -- Management interface for logging + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util.logging; + +import java.util.List; + +/** + * This interface represents the management interface for logging. + * There is a single logging bean per VM instance, which can be + * retrieved via {@link LogManager#getLoggingMXBean()}. + * + * @since 1.5 + */ +public interface LoggingMXBean +{ + /** + * Return the name of the logging level given the name of + * a logger. Returns null if no such logger exists. + * @param logger the logger's name + * @return the logging level's name, or null + */ + String getLoggerLevel(String logger); + + /** + * Return a list of all logger names. + */ + List/*<String>*/ getLoggerNames(); + + /** + * Return the name of the parent of the indicated logger. + * If no such logger exists, returns null. If the logger + * is the root logger, returns the empty string. + * @param logger the logger's name + * @return the name of the logger's parent, or null + */ + String getParentLoggerName(String logger); + + /** + * Sets the logging level for a particular logger. + * + * @param logger the name of the logger + * @param level the name of the new logging level, or null + * @throws IllegalArgumentException if the level is not + * recognized, or if the logger does not exist + * @throws SecurityException if access is denied; + * see {@link Logger#setLevel(Level)} + */ + void setLoggerLevel(String logger, String level); +} |