summaryrefslogtreecommitdiff
path: root/gnu/java
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/java')
-rw-r--r--gnu/java/awt/LowPriorityEvent.java48
-rw-r--r--gnu/java/awt/java2d/AbstractGraphics2D.java178
-rw-r--r--gnu/java/awt/java2d/ShapeCache.java85
-rw-r--r--gnu/java/awt/java2d/TexturePaintContext.java2
-rw-r--r--gnu/java/awt/peer/gtk/BufferedImageGraphics.java6
-rw-r--r--gnu/java/awt/peer/gtk/CairoGraphics2D.java213
-rw-r--r--gnu/java/awt/peer/gtk/CairoSurface.java51
-rw-r--r--gnu/java/awt/peer/gtk/FreetypeGlyphVector.java115
-rw-r--r--gnu/java/awt/peer/gtk/VolatileImageGraphics.java200
-rw-r--r--gnu/java/lang/management/MemoryMXBeanImpl.java45
-rw-r--r--gnu/java/net/PlainDatagramSocketImpl.java207
-rw-r--r--gnu/java/net/PlainSocketImpl.java352
-rw-r--r--gnu/java/net/protocol/http/HTTPURLConnection.java8
-rw-r--r--gnu/java/nio/DatagramChannelImpl.java165
-rw-r--r--gnu/java/nio/DatagramChannelSelectionKey.java13
-rw-r--r--gnu/java/nio/EpollSelectionKeyImpl.java122
-rw-r--r--gnu/java/nio/EpollSelectorImpl.java399
-rw-r--r--gnu/java/nio/FileChannelImpl.java (renamed from gnu/java/nio/channels/FileChannelImpl.java)173
-rw-r--r--gnu/java/nio/FileLockImpl.java2
-rw-r--r--gnu/java/nio/KqueueSelectionKeyImpl.java189
-rw-r--r--gnu/java/nio/KqueueSelectorImpl.java524
-rw-r--r--gnu/java/nio/NIOSocket.java29
-rw-r--r--gnu/java/nio/NIOSocketImpl.java110
-rw-r--r--gnu/java/nio/PipeImpl.java34
-rw-r--r--gnu/java/nio/SelectionKeyImpl.java1
-rw-r--r--gnu/java/nio/SelectorProviderImpl.java37
-rw-r--r--gnu/java/nio/ServerSocketChannelImpl.java39
-rw-r--r--gnu/java/nio/ServerSocketChannelSelectionKey.java13
-rw-r--r--gnu/java/nio/SocketChannelImpl.java262
-rw-r--r--gnu/java/nio/SocketChannelSelectionKey.java13
-rw-r--r--gnu/java/nio/SocketChannelSelectionKeyImpl.java11
-rw-r--r--gnu/java/nio/VMChannelOwner.java57
-rw-r--r--gnu/java/nio/charset/ByteCharset.java16
-rw-r--r--gnu/java/nio/charset/ISO_8859_1.java13
-rw-r--r--gnu/java/nio/charset/US_ASCII.java15
-rw-r--r--gnu/java/rmi/server/ActivatableRef.java8
-rw-r--r--gnu/java/util/prefs/GConfBasedPreferences.java27
-rw-r--r--gnu/java/util/prefs/gconf/GConfNativePeer.java53
-rw-r--r--gnu/java/util/regex/RETokenRepeated.java198
39 files changed, 3186 insertions, 847 deletions
diff --git a/gnu/java/awt/LowPriorityEvent.java b/gnu/java/awt/LowPriorityEvent.java
new file mode 100644
index 000000000..c1558f6ff
--- /dev/null
+++ b/gnu/java/awt/LowPriorityEvent.java
@@ -0,0 +1,48 @@
+/* LowPriorityEvent.java -- Marks events with low priority
+ 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 gnu.java.awt;
+
+/**
+ * A marker interface that marks events with low priority. LowPriority events
+ * are dispatched _after_ other (normal priority) events by the EventQueue.
+ */
+public interface LowPriorityEvent
+{
+ // Empty marker interface.
+}
diff --git a/gnu/java/awt/java2d/AbstractGraphics2D.java b/gnu/java/awt/java2d/AbstractGraphics2D.java
index 326863163..da2125398 100644
--- a/gnu/java/awt/java2d/AbstractGraphics2D.java
+++ b/gnu/java/awt/java2d/AbstractGraphics2D.java
@@ -100,6 +100,20 @@ import java.util.Map;
* {@link #updateRaster(Raster, int, int, int, int)} method, which always gets
* called after a chunk of data got painted into the raster.
* </p>
+ * <p>Alternativly the backend can provide a method for filling Shapes by
+ * overriding the protected method fillShape(). This can be accomplished
+ * by a polygon filling function of the backend. Keep in mind though that
+ * Shapes can be quite complex (i.e. non-convex and containing holes, etc)
+ * which is not supported by all polygon fillers. Also it must be noted
+ * that fillShape() is expected to handle painting and compositing as well as
+ * clipping and transformation. If your backend can't support this natively,
+ * then you can fallback to the implementation in this class. You'll need
+ * to provide a writable Raster then, see above.</p>
+ * <p>Another alternative is to implement fillScanline() which only requires
+ * the backend to be able to draw horizontal lines in device space,
+ * which is usually very cheap.
+ * The implementation should still handle painting and compositing,
+ * but no more clipping and transformation is required by the backend.</p>
* <p>The backend is free to provide implementations for the various raw*
* methods for optimized AWT 1.1 style painting of some primitives. This should
* accelerate painting of Swing greatly. When doing so, the backend must also
@@ -126,6 +140,9 @@ import java.util.Map;
* in plain Java because they involve lots of shuffling around with large
* arrays. In fact, you really would want to let the graphics card to the
* work, they are made for this.</li>
+ * <li>Provide an accelerated implementation for fillShape(). For instance,
+ * OpenGL can fill shapes very efficiently. There are some considerations
+ * to be made though, see above for details.</li>
* </ol>
* </p>
*
@@ -144,6 +161,12 @@ public abstract class AbstractGraphics2D
private static final int AA_SAMPLING = 8;
/**
+ * Caches certain shapes to avoid massive creation of such Shapes in
+ * the various draw* and fill* methods.
+ */
+ private static final ThreadLocal shapeCache = new ThreadLocal();
+
+ /**
* The transformation for this Graphics2D instance
*/
protected AffineTransform transform;
@@ -184,11 +207,6 @@ public abstract class AbstractGraphics2D
private RenderingHints renderingHints;
/**
- * The paint raster.
- */
- private Raster paintRaster;
-
- /**
* The raster of the destination surface. This is where the painting is
* performed.
*/
@@ -219,7 +237,7 @@ public abstract class AbstractGraphics2D
* AbstractGraphics2D object and will be the most commonly used setting
* in Swing rendering and should therefore be optimized as much as possible.
*/
- private boolean isOptimized;
+ private boolean isOptimized = true;
/**
* Creates a new AbstractGraphics2D instance.
@@ -270,7 +288,6 @@ public abstract class AbstractGraphics2D
public boolean drawImage(Image image, AffineTransform xform,
ImageObserver obs)
{
- boolean ret = false;
Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs),
image.getHeight(obs));
return drawImageImpl(image, xform, obs, areaOfInterest);
@@ -1144,14 +1161,31 @@ public abstract class AbstractGraphics2D
{
if (isOptimized)
{
- int tx = (int) transform.getTranslateX();
- int ty = (int) transform.getTranslateY();
- rawDrawLine(x1 + tx, y1 + ty, x2 + tx, y2 + ty);
+ rawDrawLine(x1, y1, x2, y2);
}
else
{
- Line2D line = new Line2D.Double(x1, y1, x2, y2);
- draw(line);
+ ShapeCache sc = getShapeCache();
+ if (sc.line == null)
+ sc.line = new Line2D.Float();
+ sc.line.setLine(x1, y1, x2, y2);
+ draw(sc.line);
+ }
+ }
+
+ public void drawRect(int x, int y, int w, int h)
+ {
+ if (isOptimized)
+ {
+ rawDrawRect(x, y, w, h);
+ }
+ else
+ {
+ ShapeCache sc = getShapeCache();
+ if (sc.rect == null)
+ sc.rect = new Rectangle();
+ sc.rect.setBounds(x, y, w, h);
+ draw(sc.rect);
}
}
@@ -1167,13 +1201,15 @@ public abstract class AbstractGraphics2D
{
if (isOptimized)
{
- int tx = (int) transform.getTranslateX();
- int ty = (int) transform.getTranslateY();
- rawFillRect(x + tx, y + ty, width, height);
+ rawFillRect(x, y, width, height);
}
else
{
- fill(new Rectangle(x, y, width, height));
+ ShapeCache sc = getShapeCache();
+ if (sc.rect == null)
+ sc.rect = new Rectangle();
+ sc.rect.setBounds(x, y, width, height);
+ fill(sc.rect);
}
}
@@ -1214,8 +1250,11 @@ public abstract class AbstractGraphics2D
public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
int arcHeight)
{
- draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
- arcHeight));
+ ShapeCache sc = getShapeCache();
+ if (sc.roundRect == null)
+ sc.roundRect = new RoundRectangle2D.Float();
+ sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
+ draw(sc.roundRect);
}
/**
@@ -1231,8 +1270,11 @@ public abstract class AbstractGraphics2D
public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
int arcHeight)
{
- fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
- arcHeight));
+ ShapeCache sc = getShapeCache();
+ if (sc.roundRect == null)
+ sc.roundRect = new RoundRectangle2D.Float();
+ sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
+ fill(sc.roundRect);
}
/**
@@ -1245,7 +1287,11 @@ public abstract class AbstractGraphics2D
*/
public void drawOval(int x, int y, int width, int height)
{
- draw(new Ellipse2D.Double(x, y, width, height));
+ ShapeCache sc = getShapeCache();
+ if (sc.ellipse == null)
+ sc.ellipse = new Ellipse2D.Float();
+ sc.ellipse.setFrame(x, y, width, height);
+ draw(sc.ellipse);
}
/**
@@ -1258,7 +1304,11 @@ public abstract class AbstractGraphics2D
*/
public void fillOval(int x, int y, int width, int height)
{
- fill(new Ellipse2D.Double(x, y, width, height));
+ ShapeCache sc = getShapeCache();
+ if (sc.ellipse == null)
+ sc.ellipse = new Ellipse2D.Float();
+ sc.ellipse.setFrame(x, y, width, height);
+ fill(sc.ellipse);
}
/**
@@ -1267,8 +1317,11 @@ public abstract class AbstractGraphics2D
public void drawArc(int x, int y, int width, int height, int arcStart,
int arcAngle)
{
- draw(new Arc2D.Double(x, y, width, height, arcStart, arcAngle,
- Arc2D.OPEN));
+ ShapeCache sc = getShapeCache();
+ if (sc.arc == null)
+ sc.arc = new Arc2D.Float();
+ sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.OPEN);
+ draw(sc.arc);
}
/**
@@ -1277,8 +1330,11 @@ public abstract class AbstractGraphics2D
public void fillArc(int x, int y, int width, int height, int arcStart,
int arcAngle)
{
- fill(new Arc2D.Double(x, y, width, height, arcStart, arcAngle,
- Arc2D.OPEN));
+ ShapeCache sc = getShapeCache();
+ if (sc.arc == null)
+ sc.arc = new Arc2D.Float();
+ sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.PIE);
+ draw(sc.arc);
}
public void drawPolyline(int[] xPoints, int[] yPoints, int npoints)
@@ -1292,7 +1348,13 @@ public abstract class AbstractGraphics2D
*/
public void drawPolygon(int[] xPoints, int[] yPoints, int npoints)
{
- draw(new Polygon(xPoints, yPoints, npoints));
+ ShapeCache sc = getShapeCache();
+ if (sc.polygon == null)
+ sc.polygon = new Polygon();
+ sc.polygon.xpoints = xPoints;
+ sc.polygon.ypoints = yPoints;
+ sc.polygon.npoints = npoints;
+ draw(sc.polygon);
}
/**
@@ -1300,7 +1362,13 @@ public abstract class AbstractGraphics2D
*/
public void fillPolygon(int[] xPoints, int[] yPoints, int npoints)
{
- fill(new Polygon(xPoints, yPoints, npoints));
+ ShapeCache sc = getShapeCache();
+ if (sc.polygon == null)
+ sc.polygon = new Polygon();
+ sc.polygon.xpoints = xPoints;
+ sc.polygon.ypoints = yPoints;
+ sc.polygon.npoints = npoints;
+ fill(sc.polygon);
}
/**
@@ -1461,8 +1529,12 @@ public abstract class AbstractGraphics2D
}
/**
- * Fills the specified shape. The shape has already been clipped against the
- * current clip.
+ * Fills the specified shape. Override this if your backend can efficiently
+ * fill shapes. This is possible on many systems via a polygon fill
+ * method or something similar. But keep in mind that Shapes can be quite
+ * complex (non-convex, with holes etc), which is not necessarily supported
+ * by all polygon fillers. Also note that you must perform clipping
+ * before filling the shape.
*
* @param s the shape to fill
* @param isFont <code>true</code> if the shape is a font outline
@@ -1534,6 +1606,11 @@ public abstract class AbstractGraphics2D
draw(new Line2D.Float(x0, y0, x1, y1));
}
+ protected void rawDrawRect(int x, int y, int w, int h)
+ {
+ draw(new Rectangle(x, y, w, h));
+ }
+
/**
* Draws a string in optimization mode. The implementation should respect the
* clip and translation. It can assume that the clip is a rectangle and that
@@ -1628,11 +1705,7 @@ public abstract class AbstractGraphics2D
}
/**
- * Fills the specified polygon. This should be overridden by backends
- * that support accelerated (native) polygon filling, which is the
- * case for most toolkit window and offscreen image implementations.
- *
- * The polygon is already clipped when this method is called.
+ * Fills the specified polygon without anti-aliasing.
*/
private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D,
Rectangle2D userBounds,
@@ -1663,7 +1736,7 @@ public abstract class AbstractGraphics2D
for (Iterator i = segs.iterator(); i.hasNext();)
{
PolyEdge edge = (PolyEdge) i.next();
- int yindex = (int) ((int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY));
+ int yindex = (int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY);
if (edgeTable[yindex] == null) // Create bucket when needed.
edgeTable[yindex] = new ArrayList();
edgeTable[yindex].add(edge); // Add edge to the bucket of its line.
@@ -1767,7 +1840,8 @@ public abstract class AbstractGraphics2D
}
/**
- * Paints a scanline between x0 and x1.
+ * Paints a scanline between x0 and x1. Override this when your backend
+ * can efficiently draw/fill horizontal lines.
*
* @param x0 the left offset
* @param x1 the right offset
@@ -1973,8 +2047,7 @@ public abstract class AbstractGraphics2D
// Render full scanline.
//System.err.println("scanline: " + y);
if (! emptyScanline)
- fillScanlineAA(alpha, leftX, (int) y, rightX - leftX, pCtx,
- (int) minX);
+ fillScanlineAA(alpha, leftX, y, rightX - leftX, pCtx, (int) minX);
}
pCtx.dispose();
@@ -1987,7 +2060,7 @@ public abstract class AbstractGraphics2D
*
* @param alpha the alpha values in the scanline
* @param x0 the beginning of the scanline
- * @param y the y coordinate of the line
+ * @param yy the y coordinate of the line
*/
private void fillScanlineAA(int[] alpha, int x0, int yy, int numPixels,
PaintContext pCtx, int offs)
@@ -1998,7 +2071,6 @@ public abstract class AbstractGraphics2D
Raster paintRaster = pCtx.getRaster(x0, yy, numPixels, 1);
//System.err.println("paintColorModel: " + pCtx.getColorModel());
WritableRaster aaRaster = paintRaster.createCompatibleWritableRaster();
- int numBands = paintRaster.getNumBands();
ColorModel cm = pCtx.getColorModel();
double lastAlpha = 0.;
int lastAlphaInt = 0;
@@ -2157,10 +2229,10 @@ public abstract class AbstractGraphics2D
private static Rectangle computeIntersection(int x, int y, int w, int h,
Rectangle rect)
{
- int x2 = (int) rect.x;
- int y2 = (int) rect.y;
- int w2 = (int) rect.width;
- int h2 = (int) rect.height;
+ int x2 = rect.x;
+ int y2 = rect.y;
+ int w2 = rect.width;
+ int h2 = rect.height;
int dx = (x > x2) ? x : x2;
int dy = (y > y2) ? y : y2;
@@ -2267,4 +2339,20 @@ public abstract class AbstractGraphics2D
deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY);
return segs;
}
+
+ /**
+ * Returns the ShapeCache for the calling thread.
+ *
+ * @return the ShapeCache for the calling thread
+ */
+ private ShapeCache getShapeCache()
+ {
+ ShapeCache sc = (ShapeCache) shapeCache.get();
+ if (sc == null)
+ {
+ sc = new ShapeCache();
+ shapeCache.set(sc);
+ }
+ return sc;
+ }
}
diff --git a/gnu/java/awt/java2d/ShapeCache.java b/gnu/java/awt/java2d/ShapeCache.java
new file mode 100644
index 000000000..034b53cad
--- /dev/null
+++ b/gnu/java/awt/java2d/ShapeCache.java
@@ -0,0 +1,85 @@
+/* ShapeCache.java -- Caches certain Shapes for reuse in AbstractGraphics2D
+ 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 gnu.java.awt.java2d;
+
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.RoundRectangle2D;
+
+/**
+ * Caches certain Shape objects for reuse in AbstractGraphics2D. This avoids
+ * massive creation of such objects.
+ */
+public class ShapeCache
+{
+
+ /**
+ * A cached Line2D.
+ */
+ public Line2D line;
+
+ /**
+ * A cached Rectangle.
+ */
+ public Rectangle rect;
+
+ /**
+ * A cached RoundRectangle2D.
+ */
+ public RoundRectangle2D roundRect;
+
+ /**
+ * A cached Ellipse2D.
+ */
+ public Ellipse2D ellipse;
+
+ /**
+ * A cached Arc2D.
+ */
+ public Arc2D arc;
+
+ /**
+ * A cached Polygon.
+ */
+ public Polygon polygon;
+
+}
diff --git a/gnu/java/awt/java2d/TexturePaintContext.java b/gnu/java/awt/java2d/TexturePaintContext.java
index 1a782ce07..840b61456 100644
--- a/gnu/java/awt/java2d/TexturePaintContext.java
+++ b/gnu/java/awt/java2d/TexturePaintContext.java
@@ -104,7 +104,7 @@ public class TexturePaintContext
double scaleY = anchor.getHeight() / image.getHeight();
transform = (AffineTransform) xform.clone();
transform.scale(scaleX, scaleY);
- transform.translate(-anchor.getMinX(), -anchor.getMaxX());
+ transform.translate(-anchor.getMinX(), -anchor.getMinY());
transform = transform.createInverse();
}
catch (NoninvertibleTransformException ex)
diff --git a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
index 5412cbea9..e188d3fd0 100644
--- a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
+++ b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java
@@ -158,6 +158,7 @@ public class BufferedImageGraphics extends CairoGraphics2D
BufferedImageGraphics(BufferedImageGraphics copyFrom)
{
+ image = copyFrom.image;
surface = copyFrom.surface;
cairo_t = surface.newCairoContext();
imageWidth = copyFrom.imageWidth;
@@ -182,6 +183,9 @@ public class BufferedImageGraphics extends CairoGraphics2D
width = imageWidth - x;
if( y + height > imageHeight )
height = imageHeight - y;
+
+ boolean wasPremultiplied = image.isAlphaPremultiplied();
+ image.coerceData(true);
if( !hasFastCM )
image.setRGB(x, y, width, height, pixels,
@@ -190,6 +194,8 @@ public class BufferedImageGraphics extends CairoGraphics2D
System.arraycopy(pixels, y * imageWidth,
((DataBufferInt)image.getRaster().getDataBuffer()).
getData(), y * imageWidth, height * imageWidth);
+
+ image.coerceData(wasPremultiplied);
}
/**
diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
index 8fe04fe77..fd69c9b48 100644
--- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java
+++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
@@ -45,6 +45,7 @@ import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
+import java.awt.CompositeContext;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
@@ -53,6 +54,8 @@ import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
@@ -161,6 +164,7 @@ public abstract class CairoGraphics2D extends Graphics2D
* The current compositing context, if any.
*/
Composite comp;
+ CompositeContext compCtx;
/**
* Rendering hint map.
@@ -190,6 +194,18 @@ public abstract class CairoGraphics2D extends Graphics2D
0xFF000000);
/**
+ * Native constants for interpolation methods.
+ * Note, this corresponds to an enum in native/jni/gtk-peer/cairographics2d.h
+ */
+ public static final int INTERPOLATION_NEAREST = 0,
+ INTERPOLATION_BILINEAR = 1,
+ INTERPOLATION_BICUBIC = 5,
+ ALPHA_INTERPOLATION_SPEED = 2,
+ ALPHA_INTERPOLATION_QUALITY = 3,
+ ALPHA_INTERPOLATION_DEFAULT = 4;
+ // TODO: Does ALPHA_INTERPOLATION really correspond to CAIRO_FILTER_FAST/BEST/GOOD?
+
+ /**
* Constructor does nothing.
*/
public CairoGraphics2D()
@@ -220,6 +236,7 @@ public abstract class CairoGraphics2D extends Graphics2D
nativePointer = init(cairo_t_pointer);
paint = g.paint;
stroke = g.stroke;
+ comp = g.comp;
setRenderingHints(g.hints);
Color foreground;
@@ -254,6 +271,7 @@ public abstract class CairoGraphics2D extends Graphics2D
setStroke(stroke);
setTransformImpl(transform);
setClip(clip);
+ setComposite(comp);
}
/**
@@ -274,6 +292,8 @@ public abstract class CairoGraphics2D extends Graphics2D
{
disposeNative(nativePointer);
nativePointer = 0;
+ if (compCtx != null)
+ compCtx.dispose();
}
/**
@@ -309,15 +329,16 @@ public abstract class CairoGraphics2D extends Graphics2D
* @param i2u - affine transform array
*/
private native void drawPixels(long pointer, int[] pixels, int w, int h,
- int stride, double[] i2u, double alpha);
+ int stride, double[] i2u, double alpha,
+ int interpolation);
private native void setGradient(long pointer, double x1, double y1,
double x2, double y2,
int r1, int g1, int b1, int a1, int r2,
int g2, int b2, int a2, boolean cyclic);
- private native void setTexturePixels(long pointer, int[] pixels, int w,
- int h, int stride);
+ private native void setPaintPixels(long pointer, int[] pixels, int w,
+ int h, int stride, boolean repeat);
/**
* Set the current transform matrix
@@ -441,11 +462,6 @@ public abstract class CairoGraphics2D extends Graphics2D
private native void cairoResetClip(long pointer);
/**
- * Set interpolation types
- */
- private native void cairoSurfaceSetFilter(long pointer, int filter);
-
- /**
* Draws a line from (x1,y1) to (x2,y2).
*
* @param pointer the native pointer
@@ -666,7 +682,7 @@ public abstract class CairoGraphics2D extends Graphics2D
public void setPaint(Paint p)
{
- if (paint == null)
+ if (p == null)
return;
paint = p;
@@ -690,7 +706,7 @@ public abstract class CairoGraphics2D extends Graphics2D
AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
BufferedImage texture = op.filter(img, null);
int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
- setTexturePixels(nativePointer, pixels, width, height, width);
+ setPaintPixels(nativePointer, pixels, width, height, width, true);
}
else if (paint instanceof GradientPaint)
{
@@ -705,7 +721,52 @@ public abstract class CairoGraphics2D extends Graphics2D
gp.isCyclic());
}
else
- throw new java.lang.UnsupportedOperationException();
+ {
+ // Get bounds in device space
+ int minX = 0;
+ int minY = 0;
+ int width = (int)getRealBounds().getWidth();
+ int height = (int)getRealBounds().getHeight();
+
+ Point2D origin = transform.transform(new Point2D.Double(minX, minY),
+ null);
+ Point2D extreme = transform.transform(new Point2D.Double(width + minX,
+ height + minY),
+ null);
+ minX = (int)origin.getX();
+ minY = (int)origin.getY();
+ width = (int)extreme.getX() - minX;
+ height = (int)extreme.getY() - minY;
+
+ // Get raster of the paint background
+ PaintContext pc = paint.createContext(ColorModel.getRGBdefault(),
+ new Rectangle(minX, minY,
+ width, height),
+ getRealBounds(),
+ transform, hints);
+
+ Raster raster = pc.getRaster(minX, minY, width, height);
+
+ // Work around colorspace issues, and force use of the
+ // BufferedImage.getRGB method... this can be improved upon.
+ WritableRaster wr = Raster.createWritableRaster(raster.getSampleModel(),
+ new Point(raster.getMinX(),
+ raster.getMinY()));
+ wr.setRect(raster);
+
+ BufferedImage img2 = new BufferedImage(pc.getColorModel(), wr,
+ pc.getColorModel().isAlphaPremultiplied(),
+ null);
+
+ // Set pixels in cairo
+ setPaintPixels(nativePointer,
+ img2.getRGB(0, 0, width, height, null, 0, width),
+ width, height, width, false);
+ // setPaintPixels(nativePointer,
+ // raster.getPixels(0, 0, width, height, (int[])null),
+ // width, height, width, false);
+ // doesn't work... but would be much more efficient!
+ }
}
public Stroke getStroke()
@@ -896,13 +957,23 @@ public abstract class CairoGraphics2D extends Graphics2D
*/
public void setComposite(Composite comp)
{
+ if (this.comp == comp)
+ return;
+
this.comp = comp;
+ if (compCtx != null)
+ compCtx.dispose();
+ compCtx = null;
+ if (comp == null)
+ comp = AlphaComposite.SrcOver;
+
if (comp instanceof AlphaComposite)
{
AlphaComposite a = (AlphaComposite) comp;
cairoSetOperator(nativePointer, a.getRule());
}
+
else
{
// FIXME: this check is only required "if this Graphics2D
@@ -912,9 +983,26 @@ public abstract class CairoGraphics2D extends Graphics2D
sm.checkPermission(new AWTPermission("readDisplayPixels"));
// FIXME: implement general Composite support
- throw new java.lang.UnsupportedOperationException();
+ //throw new java.lang.UnsupportedOperationException();
+ // this is in progress! yay!
+ compCtx = comp.createContext(getNativeCM(), getNativeCM(), hints);
}
}
+
+ /**
+ * Returns the Colour Model describing the native, raw image data for this
+ * specific peer.
+ *
+ * @return ColorModel the ColorModel of native data in this peer
+ */
+ /* protected abstract ColorModel getNativeCM(); */
+ protected ColorModel getNativeCM()
+ {
+ // This stub should be removed and the method made abstract once I'm done
+ // implementing custom composites across all the peers... but we need it
+ // for now, so that the build doesn't break.
+ return null;
+ }
///////////////////////// DRAWING PRIMITIVES ///////////////////////////////////
@@ -1006,8 +1094,14 @@ public abstract class CairoGraphics2D extends Graphics2D
{
if (bg != null)
cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0,
- bg.getGreen() / 255.0, bg.getBlue() / 255.0, 1.0);
+ bg.getGreen() / 255.0, bg.getBlue() / 255.0,
+ bg.getAlpha() / 255.0);
+
+ Composite oldcomp = comp;
+ setComposite(AlphaComposite.Src);
fillRect(x, y, width, height);
+
+ setComposite(oldcomp);
updateColor();
}
@@ -1054,7 +1148,10 @@ public abstract class CairoGraphics2D extends Graphics2D
public void fillRect(int x, int y, int width, int height)
{
- cairoFillRect(nativePointer, x, y, width, height);
+ fill(new Rectangle(x, y, width, height));
+ // TODO: If we want to use the more efficient
+ //cairoFillRect(nativePointer, x, y, width, height);
+ // we need to override this method in subclasses
}
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
@@ -1150,32 +1247,10 @@ public abstract class CairoGraphics2D extends Graphics2D
///////////////////////// RENDERING HINTS ///////////////////////////////////
- /**
- * FIXME- support better
- */
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
{
hints.put(hintKey, hintValue);
- if (hintKey.equals(RenderingHints.KEY_INTERPOLATION)
- || hintKey.equals(RenderingHints.KEY_ALPHA_INTERPOLATION))
- {
- if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
- cairoSurfaceSetFilter(nativePointer, 0);
-
- else if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
- cairoSurfaceSetFilter(nativePointer, 1);
-
- else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
- cairoSurfaceSetFilter(nativePointer, 2);
-
- else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
- cairoSurfaceSetFilter(nativePointer, 3);
-
- else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
- cairoSurfaceSetFilter(nativePointer, 4);
- }
-
shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
|| hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
}
@@ -1189,30 +1264,15 @@ public abstract class CairoGraphics2D extends Graphics2D
{
this.hints = new RenderingHints(getDefaultHints());
this.hints.add(new RenderingHints(hints));
-
- if (hints.containsKey(RenderingHints.KEY_INTERPOLATION))
- {
- if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
- cairoSurfaceSetFilter(nativePointer, 0);
-
- else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
- cairoSurfaceSetFilter(nativePointer, 1);
- }
-
- if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION))
- {
- if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
- cairoSurfaceSetFilter(nativePointer, 2);
-
- else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
- cairoSurfaceSetFilter(nativePointer, 3);
-
- else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
- cairoSurfaceSetFilter(nativePointer, 4);
- }
-
+
shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
|| hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
+
+ if (compCtx != null)
+ {
+ compCtx.dispose();
+ compCtx = comp.createContext(getNativeCM(), getNativeCM(), this.hints);
+ }
}
public void addRenderingHints(Map hints)
@@ -1224,6 +1284,30 @@ public abstract class CairoGraphics2D extends Graphics2D
{
return hints;
}
+
+ private int getInterpolation()
+ {
+ if (this.hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
+ return INTERPOLATION_NEAREST;
+
+ else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
+ return INTERPOLATION_BILINEAR;
+
+ else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC))
+ return INTERPOLATION_BICUBIC;
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
+ return ALPHA_INTERPOLATION_SPEED;
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
+ return ALPHA_INTERPOLATION_QUALITY;
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
+ return ALPHA_INTERPOLATION_DEFAULT;
+
+ // Do bilinear interpolation as default
+ return INTERPOLATION_BILINEAR;
+ }
///////////////////////// IMAGE. METHODS ///////////////////////////////////
@@ -1273,6 +1357,9 @@ public abstract class CairoGraphics2D extends Graphics2D
double[] i2u = new double[6];
int width = b.getWidth();
int height = b.getHeight();
+
+ boolean wasPremultplied = b.isAlphaPremultiplied();
+ b.coerceData(true);
// If this BufferedImage has a BufferedImageGraphics object,
// use the cached CairoSurface that BIG is drawing onto
@@ -1290,8 +1377,10 @@ public abstract class CairoGraphics2D extends Graphics2D
if(raster instanceof CairoSurface)
{
- ((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha);
+ ((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha,
+ getInterpolation());
updateColor();
+ b.coerceData(wasPremultplied);
return true;
}
@@ -1310,10 +1399,12 @@ public abstract class CairoGraphics2D extends Graphics2D
int[] pixels = b.getRGB(0, 0, width, height, null, 0, width);
- drawPixels(nativePointer, pixels, width, height, width, i2u, alpha);
+ drawPixels(nativePointer, pixels, width, height, width, i2u, alpha,
+ getInterpolation());
// Cairo seems to lose the current color which must be restored.
updateColor();
+ b.coerceData(wasPremultplied);
return true;
}
@@ -1626,7 +1717,7 @@ public abstract class CairoGraphics2D extends Graphics2D
if (comp instanceof AlphaComposite)
alpha = ((AlphaComposite) comp).getAlpha();
drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(),
- r.getWidth(), i2u, alpha);
+ r.getWidth(), i2u, alpha, getInterpolation());
// Cairo seems to lose the current color which must be restored.
updateColor();
diff --git a/gnu/java/awt/peer/gtk/CairoSurface.java b/gnu/java/awt/peer/gtk/CairoSurface.java
index 3bf9a9ccf..91b10369d 100644
--- a/gnu/java/awt/peer/gtk/CairoSurface.java
+++ b/gnu/java/awt/peer/gtk/CairoSurface.java
@@ -38,15 +38,18 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
-import java.awt.Point;
+import gnu.java.awt.Buffers;
+
import java.awt.Graphics2D;
-import java.awt.image.DataBuffer;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
+import java.awt.Point;
+import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
import java.awt.image.DirectColorModel;
+import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
import java.nio.ByteOrder;
import java.util.Hashtable;
@@ -69,11 +72,15 @@ public class CairoSurface extends WritableRaster
*/
long bufferPointer;
- static ColorModel nativeModel = new DirectColorModel(32,
- 0x00FF0000,
- 0x0000FF00,
- 0x000000FF,
- 0xFF000000);
+ // nativeGetPixels will return [0]=red, [1]=green, [2]=blue, [3]=alpha
+ static ColorModel nativeColorModel = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000,
+ true,
+ Buffers.smallestAppropriateTransferType(32));
/**
* Allocates and clears the buffer and creates the cairo surface.
@@ -102,11 +109,13 @@ public class CairoSurface extends WritableRaster
* with an affine transform given by i2u.
*/
public native void nativeDrawSurface(long surfacePointer, long contextPointer,
- double[] i2u, double alpha);
+ double[] i2u, double alpha,
+ int interpolation);
- public void drawSurface(long contextPointer, double[] i2u, double alpha)
+ public void drawSurface(long contextPointer, double[] i2u, double alpha,
+ int interpolation)
{
- nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha);
+ nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha, interpolation);
}
/**
@@ -138,10 +147,8 @@ public class CairoSurface extends WritableRaster
*/
public CairoSurface(int width, int height)
{
- super( new SinglePixelPackedSampleModel
- (DataBuffer.TYPE_INT, width, height,
- new int[]{ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }),
- null, new Point(0, 0) );
+ super(createNativeSampleModel(width, height),
+ null, new Point(0, 0));
if(width <= 0 || height <= 0)
throw new IllegalArgumentException("Image must be at least 1x1 pixels.");
@@ -253,7 +260,7 @@ public class CairoSurface extends WritableRaster
*/
public static BufferedImage getBufferedImage(CairoSurface surface)
{
- return new BufferedImage(nativeModel, surface, true, new Hashtable());
+ return new BufferedImage(nativeColorModel, surface, true, new Hashtable());
}
private class CairoDataBuffer extends DataBuffer
@@ -315,4 +322,14 @@ public class CairoSurface extends WritableRaster
{
copyAreaNative2(bufferPointer, x, y, width, height, dx, dy, stride);
}
+
+ /**
+ * Creates a SampleModel that matches Cairo's native format
+ */
+ protected static SampleModel createNativeSampleModel(int w, int h)
+ {
+ return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h,
+ new int[]{0x000000FF, 0x0000FF00,
+ 0x00FF0000, 0xFF000000});
+ }
}
diff --git a/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
index 2c9d91793..44c1ad926 100644
--- a/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
+++ b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
@@ -39,14 +39,15 @@ package gnu.java.awt.peer.gtk;
import java.awt.Font;
import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.GeneralPath;
+import java.awt.font.FontRenderContext;
import java.awt.font.GlyphJustificationInfo;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
-import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
public class FreetypeGlyphVector extends GlyphVector
{
@@ -155,14 +156,15 @@ public class FreetypeGlyphVector extends GlyphVector
}
glyphCodes = new int[ nGlyphs ];
- glyphPositions = new float[ nGlyphs ];
+ glyphPositions = new float[(nGlyphs + 1) * 2];
glyphTransforms = new AffineTransform[ nGlyphs ];
for(int i = 0; i < nGlyphs; i++ )
{
- glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] );
- glyphCodes[i] = gv.glyphCodes[ i ];
- glyphPositions[i] = gv.glyphPositions[ i ];
+ glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] );
+ glyphCodes[i] = gv.glyphCodes[ i ];
}
+ System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0,
+ glyphPositions.length);
}
/**
@@ -242,22 +244,31 @@ public class FreetypeGlyphVector extends GlyphVector
public void performDefaultLayout()
{
logicalBounds = null; // invalidate caches.
- glyphPositions = null;
-
- glyphTransforms = new AffineTransform[ nGlyphs ];
- double x = 0;
+ glyphTransforms = new AffineTransform[nGlyphs];
+ Arrays.fill(glyphTransforms, null);
+ glyphPositions = new float[(nGlyphs + 1) * 2];
+ GlyphMetrics gm = null;
+ float x = 0;
+ float y = 0;
for(int i = 0; i < nGlyphs; i++)
{
- GlyphMetrics gm = getGlyphMetrics( i );
- glyphTransforms[ i ] = AffineTransform.getTranslateInstance(x, 0);
- x += gm.getAdvanceX();
- if( i > 0 )
- {
- Point2D p = getKerning( glyphCodes[ i - 1 ], glyphCodes[ i ] );
- x += p.getX();
- }
+ gm = getGlyphMetrics( i );
+ glyphPositions[i*2] = x;
+ glyphPositions[i*2 + 1] = y;
+
+ x += gm.getAdvanceX();
+ y += gm.getAdvanceY();
+
+ if (i != nGlyphs-1)
+ {
+ Point2D p = getKerning(glyphCodes[i], glyphCodes[i + 1]);
+ x += p.getX();
+ y += p.getY();
+ }
}
+ glyphPositions[nGlyphs * 2] = x;
+ glyphPositions[nGlyphs * 2 + 1] = y;
}
/**
@@ -286,9 +297,6 @@ public class FreetypeGlyphVector extends GlyphVector
return rval;
}
- /**
- * FIXME: Implement me.
- */
public Shape getGlyphLogicalBounds(int glyphIndex)
{
GlyphMetrics gm = getGlyphMetrics( glyphIndex );
@@ -296,10 +304,17 @@ public class FreetypeGlyphVector extends GlyphVector
return null;
Rectangle2D r = gm.getBounds2D();
Point2D p = getGlyphPosition( glyphIndex );
- return new Rectangle2D.Double( p.getX() + r.getX() - gm.getLSB(),
- p.getY() + r.getY(),
- gm.getAdvanceX(),
- r.getHeight() );
+
+ double[] bounds = new double[] {p.getX() + r.getX() - gm.getLSB(),
+ p.getY() + r.getY(),
+ p.getX() + r.getX() - gm.getLSB() + gm.getAdvanceX(),
+ p.getY() + r.getY() + r.getHeight()};
+
+ if (glyphTransforms[glyphIndex] != null)
+ glyphTransforms[glyphIndex].transform(bounds, 0, bounds, 0, 4);
+
+ return new Rectangle2D.Double(bounds[0], bounds[1], bounds[2] - bounds[0],
+ bounds[3] - bounds[1]);
}
/*
@@ -352,7 +367,9 @@ public class FreetypeGlyphVector extends GlyphVector
public Shape getGlyphOutline(int glyphIndex)
{
GeneralPath gp = getGlyphOutlineNative( glyphCodes[ glyphIndex ] );
- gp.transform( glyphTransforms[ glyphIndex ] );
+ if (glyphTransforms[glyphIndex] != null)
+ gp.transform( glyphTransforms[glyphIndex]);
+
return gp;
}
@@ -361,8 +378,8 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public Point2D getGlyphPosition(int glyphIndex)
{
- return glyphTransforms[ glyphIndex ].transform( new Point2D.Double(0, 0),
- null );
+ return new Point2D.Float(glyphPositions[glyphIndex*2],
+ glyphPositions[glyphIndex*2 + 1]);
}
/**
@@ -371,25 +388,12 @@ public class FreetypeGlyphVector extends GlyphVector
public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
float[] positionReturn)
{
- if( glyphPositions != null )
- return glyphPositions;
-
- float[] rval;
-
- if( positionReturn == null )
- rval = new float[2 * numEntries];
- else
- rval = positionReturn;
-
- for( int i = beginGlyphIndex; i < numEntries; i++ )
- {
- Point2D p = getGlyphPosition( i );
- rval[i * 2] = (float)p.getX();
- rval[i * 2 + 1] = (float)p.getY();
- }
-
- glyphPositions = rval;
- return rval;
+ if (positionReturn == null)
+ positionReturn = new float[numEntries*2];
+
+ System.arraycopy(glyphPositions, beginGlyphIndex*2, positionReturn, 0,
+ numEntries*2);
+ return positionReturn;
}
/**
@@ -397,7 +401,7 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public AffineTransform getGlyphTransform(int glyphIndex)
{
- return new AffineTransform( glyphTransforms[ glyphIndex ] );
+ return glyphTransforms[glyphIndex];
}
/**
@@ -485,11 +489,9 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public void setGlyphPosition(int glyphIndex, Point2D newPos)
{
- // FIXME: Scaling, etc.?
- glyphTransforms[ glyphIndex ].setToTranslation( newPos.getX(),
- newPos.getY() );
+ glyphPositions[glyphIndex*2] = (float)(newPos.getX());
+ glyphPositions[glyphIndex*2 + 1] = (float)(newPos.getY());
logicalBounds = null;
- glyphPositions = null;
}
/**
@@ -497,8 +499,7 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public void setGlyphTransform(int glyphIndex, AffineTransform newTX)
{
- glyphTransforms[ glyphIndex ].setTransform( newTX );
logicalBounds = null;
- glyphPositions = null;
+ glyphTransforms[glyphIndex] = newTX;
}
}
diff --git a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
index 584965593..560d31750 100644
--- a/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
+++ b/gnu/java/awt/peer/gtk/VolatileImageGraphics.java
@@ -38,15 +38,31 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
+import java.awt.AlphaComposite;
+import java.awt.Color;
import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
+import java.awt.Point;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
public class VolatileImageGraphics extends ComponentGraphics
{
private GtkVolatileImage owner;
+ private BufferedImage buffer;
public VolatileImageGraphics(GtkVolatileImage img)
{
@@ -77,10 +93,118 @@ public class VolatileImageGraphics extends ComponentGraphics
return new VolatileImageGraphics( this );
}
+ public void draw(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.draw(s);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setColor(this.getColor());
+ g2d.setStroke(this.getStroke());
+ g2d.draw(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void fill(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.fill(s);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void drawGlyphVector(GlyphVector gv, float x, float y)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawGlyphVector(gv, x, y);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.drawGlyphVector(gv, x, y);
+
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ drawComposite(bounds, null);
+ }
+ }
+
+ protected boolean drawImage(Image img, AffineTransform xform,
+ Color bgcolor, ImageObserver obs)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ return super.drawImage(img, xform, bgcolor, obs);
+
+ // Custom composite
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find dimensions of translation
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth(), bImg.getHeight());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+ // Perform compositing from buffer to screen
+ return drawComposite(new Rectangle2D.Double((int)origin.getX(),
+ (int)origin.getY(),
+ (int)pt.getX(),
+ (int)pt.getY()),
+ obs);
+ }
+ }
+
public boolean drawImage(Image img, int x, int y, ImageObserver observer)
{
- if( img instanceof GtkVolatileImage )
+ if (img instanceof GtkVolatileImage
+ && (comp == null || comp instanceof AlphaComposite))
{
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
x, y,
@@ -94,7 +218,8 @@ public class VolatileImageGraphics extends ComponentGraphics
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer)
{
- if( img instanceof GtkVolatileImage )
+ if ((img instanceof GtkVolatileImage)
+ && (comp == null || comp instanceof AlphaComposite))
{
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
x, y, width, height );
@@ -107,5 +232,76 @@ public class VolatileImageGraphics extends ComponentGraphics
{
return new Rectangle2D.Double(0, 0, owner.width, owner.height);
}
+
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+ {
+ // Clip source to visible areas that need updating
+ Rectangle2D clip = this.getClipBounds();
+ Rectangle2D.intersect(bounds, clip, bounds);
+
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Get current on-screen pixels (destination) and clip to bounds
+ BufferedImage current = owner.getSnapshot();
+
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+
+ Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
+ points[2] - points[0],
+ points[3] - points[1]);
+ Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
+
+ current = current.getSubimage((int)deviceBounds.getX(),
+ (int)deviceBounds.getY(),
+ (int)deviceBounds.getWidth(),
+ (int)deviceBounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), current.getRaster(),
+ buffer2.getRaster());
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ boolean rv = super.drawImage(buffer2,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ null, null);
+
+ return rv;
+ }
+
+ private void createBuffer()
+ {
+ if (buffer == null)
+ {
+ WritableRaster rst;
+ rst = Raster.createWritableRaster(CairoSurface.
+ createNativeSampleModel(owner.width,
+ owner.height),
+ new Point(0,0));
+
+ buffer = new BufferedImage(CairoSurface.nativeColorModel, rst, true,
+ new Hashtable());
+ }
+ else
+ {
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ }
+ }
+
+ protected ColorModel getNativeCM()
+ {
+ return CairoSurface.nativeColorModel;
+ }
}
diff --git a/gnu/java/lang/management/MemoryMXBeanImpl.java b/gnu/java/lang/management/MemoryMXBeanImpl.java
index 064e19a19..8cb104202 100644
--- a/gnu/java/lang/management/MemoryMXBeanImpl.java
+++ b/gnu/java/lang/management/MemoryMXBeanImpl.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package gnu.java.lang.management;
+import gnu.classpath.ListenerData;
+
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MemoryUsage;
@@ -168,49 +170,6 @@ public final class MemoryMXBeanImpl
VMMemoryMXBeanImpl.setVerbose(verbose);
}
- private class ListenerData
- {
- private NotificationListener listener;
- private NotificationFilter filter;
- private Object passback;
-
- public ListenerData(NotificationListener listener,
- NotificationFilter filter, Object passback)
- {
- this.listener = listener;
- this.filter = filter;
- this.passback = passback;
- }
-
- public NotificationListener getListener()
- {
- return listener;
- }
-
- public NotificationFilter getFilter()
- {
- return filter;
- }
-
- public Object getPassback()
- {
- return passback;
- }
-
- public boolean equals(Object obj)
- {
- if (obj instanceof ListenerData)
- {
- ListenerData data = (ListenerData) obj;
- return (data.getListener() == listener &&
- data.getFilter() == filter &&
- data.getPassback() == passback);
- }
- return false;
- }
-
- }
-
public void addNotificationListener(NotificationListener listener,
NotificationFilter filter,
Object passback)
diff --git a/gnu/java/net/PlainDatagramSocketImpl.java b/gnu/java/net/PlainDatagramSocketImpl.java
index 0fcd780df..be2fc796b 100644
--- a/gnu/java/net/PlainDatagramSocketImpl.java
+++ b/gnu/java/net/PlainDatagramSocketImpl.java
@@ -38,13 +38,20 @@ exception statement from your version. */
package gnu.java.net;
+import gnu.java.nio.VMChannel;
+
import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.lang.reflect.Field;
import java.net.DatagramPacket;
import java.net.DatagramSocketImpl;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
/**
* Written using on-line Java Platform 1.2 API Specification, as well
@@ -62,11 +69,13 @@ import java.net.SocketException;
*/
public final class PlainDatagramSocketImpl extends DatagramSocketImpl
{
-
+
+ private final VMChannel channel;
+
/**
- * This is the actual underlying file descriptor
+ * The platform-specific socket implementation.
*/
- int native_fd = -1;
+ private final VMPlainSocketImpl impl;
/**
* Lock object to serialize threads wanting to receive
@@ -81,25 +90,26 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
/**
* Default do nothing constructor
*/
- public PlainDatagramSocketImpl()
+ public PlainDatagramSocketImpl() throws IOException
{
- // Nothing to do here.
+ channel = new VMChannel();
+ impl = new VMPlainSocketImpl(channel);
}
- protected void finalize() throws Throwable
+ /*protected void finalize() throws Throwable
{
synchronized (this)
{
- if (native_fd != -1)
+ if (channel.getState().isValid())
close();
}
super.finalize();
- }
+ }*/
- public int getNativeFD()
+ /*public int getNativeFD()
{
return native_fd;
- }
+ }*/
/**
* Binds this socket to a particular port and interface
@@ -109,20 +119,46 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*
* @exception SocketException If an error occurs
*/
- protected synchronized void bind(int port, InetAddress addr)
+ protected synchronized void bind(int port, InetAddress addr)
throws SocketException
- {
- VMPlainDatagramSocketImpl.bind(this, port, addr);
- }
+ {
+ try
+ {
+ impl.bind(new InetSocketAddress(addr, port));
+ }
+ catch (SocketException se)
+ {
+ throw se;
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
+ }
/**
* Creates a new datagram socket
*
* @exception SocketException If an error occurs
*/
- protected synchronized void create() throws SocketException
+ protected synchronized void create() throws SocketException
{
- VMPlainDatagramSocketImpl.create(this);
+ try
+ {
+ channel.initSocket(false);
+ }
+ catch (SocketException se)
+ {
+ throw se;
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
}
/**
@@ -147,8 +183,14 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
{
synchronized (this)
{
- if (native_fd != -1)
- close();
+ try
+ {
+ if (channel.getState().isValid())
+ channel.disconnect();
+ }
+ catch (IOException ioe)
+ {
+ }
}
}
@@ -181,6 +223,23 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
return ((Integer) obj).intValue();
}
+ protected int getLocalPort()
+ {
+ if (channel == null)
+ return -1;
+
+ try
+ {
+ InetSocketAddress local = channel.getLocalAddress();
+ if (local == null)
+ return -1;
+ return local.getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
+ }
/**
* Sends a packet of data to a remote host
@@ -191,13 +250,30 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected void send(DatagramPacket packet) throws IOException
{
- if (native_fd != -1)
+ synchronized (SEND_LOCK)
{
- synchronized(SEND_LOCK)
+ ByteBuffer buf = ByteBuffer.wrap(packet.getData(),
+ packet.getOffset(),
+ packet.getLength());
+ InetAddress remote = packet.getAddress();
+ int port = packet.getPort();
+ if (remote == null)
+ throw new NullPointerException();
+ if (port <= 0)
+ throw new SocketException("invalid port " + port);
+ while (true)
{
- VMPlainDatagramSocketImpl.send(this, packet);
+ try
+ {
+ channel.send(buf, new InetSocketAddress(remote, port));
+ break;
+ }
+ catch (InterruptedIOException ioe)
+ {
+ // Ignore; interrupted system call.
+ }
}
- }
+ }
}
/**
@@ -210,10 +286,32 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
protected void receive(DatagramPacket packet)
throws IOException
{
- synchronized(RECEIVE_LOCK)
- {
- VMPlainDatagramSocketImpl.receive(this, packet);
- }
+ synchronized(RECEIVE_LOCK)
+ {
+ ByteBuffer buf = ByteBuffer.wrap(packet.getData(),
+ packet.getOffset(),
+ packet.getLength());
+ SocketAddress addr = null;
+ while (true)
+ {
+ try
+ {
+ addr = channel.receive(buf);
+ break;
+ }
+ catch (SocketTimeoutException ste)
+ {
+ throw ste;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignore. Loop.
+ }
+ }
+ if (addr != null)
+ packet.setSocketAddress(addr);
+ packet.setLength(buf.position() - packet.getOffset());
+ }
}
@@ -227,9 +325,9 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
public synchronized void setOption(int option_id, Object val)
throws SocketException
- {
- VMPlainDatagramSocketImpl.setOption(this, option_id, val);
- }
+ {
+ impl.setOption(option_id, val);
+ }
/**
* Retrieves the value of an option on the socket
@@ -242,16 +340,43 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
public synchronized Object getOption(int option_id)
throws SocketException
- {
- return VMPlainDatagramSocketImpl.getOption(this, option_id);
- }
+ {
+ if (option_id == SO_BINDADDR)
+ {
+ try
+ {
+ InetSocketAddress local = channel.getLocalAddress();
+ if (local == null)
+ return null;
+ return local.getAddress();
+ }
+ catch (SocketException se)
+ {
+ throw se;
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
+ }
+ return impl.getOption(option_id);
+ }
/**
* Closes the socket
*/
protected synchronized void close()
{
- VMPlainDatagramSocketImpl.close(this);
+ try
+ {
+ if (channel.getState().isValid())
+ channel.close();
+ }
+ catch (IOException ioe)
+ {
+ }
}
/**
@@ -291,7 +416,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void join(InetAddress addr) throws IOException
{
- VMPlainDatagramSocketImpl.join(this,addr);
+ impl.join(addr);
}
/**
@@ -303,7 +428,7 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void leave(InetAddress addr) throws IOException
{
- VMPlainDatagramSocketImpl.leave(this, addr);
+ impl.leave(addr);
}
/**
@@ -323,12 +448,20 @@ public final class PlainDatagramSocketImpl extends DatagramSocketImpl
public void joinGroup(SocketAddress address, NetworkInterface netIf)
throws IOException
{
- VMPlainDatagramSocketImpl.joinGroup(this, address, netIf);
+ if (address == null)
+ throw new NullPointerException();
+ if (!(address instanceof InetSocketAddress))
+ throw new SocketException("unknown address type");
+ impl.joinGroup((InetSocketAddress) address, netIf);
}
public void leaveGroup(SocketAddress address, NetworkInterface netIf)
throws IOException
{
- VMPlainDatagramSocketImpl.leaveGroup(this, address, netIf);
+ if (address == null)
+ throw new NullPointerException();
+ if (!(address instanceof InetSocketAddress))
+ throw new SocketException("unknown address type");
+ impl.leaveGroup((InetSocketAddress) address, netIf);
}
}
diff --git a/gnu/java/net/PlainSocketImpl.java b/gnu/java/net/PlainSocketImpl.java
index 47d05aa41..750243d5d 100644
--- a/gnu/java/net/PlainSocketImpl.java
+++ b/gnu/java/net/PlainSocketImpl.java
@@ -39,13 +39,24 @@ exception statement from your version. */
package gnu.java.net;
+import gnu.java.nio.SelectorProviderImpl;
+import gnu.java.nio.SocketChannelImpl;
+import gnu.java.nio.VMChannel;
+import gnu.java.security.action.GetSecurityPropertyAction;
+
+import java.io.EOFException;
import java.io.InputStream;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
/**
* Written using on-line Java Platform 1.2 API Specification, as well
@@ -63,17 +74,13 @@ import java.net.SocketImpl;
* @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
* @author Aaron M. Renn (arenn@urbanophile.com)
*/
-public final class PlainSocketImpl extends SocketImpl
+public class PlainSocketImpl extends SocketImpl
{
/**
- * The OS file handle representing the socket.
- * This is used for reads and writes to/from the socket and
- * to close it.
- *
- * When the socket is closed this is reset to -1.
+ * The underlying plain socket VM implementation.
*/
- int native_fd = -1;
+ protected VMPlainSocketImpl impl;
/**
* A cached copy of the in stream for reading from the socket.
@@ -90,7 +97,13 @@ public final class PlainSocketImpl extends SocketImpl
* is being invoked on this socket.
*/
private boolean inChannelOperation;
-
+
+ /**
+ * The socket channel we use for IO operation. Package-private for
+ * use by inner classes.
+ */
+ SocketChannelImpl channel;
+
/**
* Indicates whether we should ignore whether any associated
* channel is set to non-blocking mode. Certain operations
@@ -117,29 +130,7 @@ public final class PlainSocketImpl extends SocketImpl
*/
public PlainSocketImpl()
{
- // Nothing to do here.
- }
-
- protected void finalize() throws Throwable
- {
- synchronized (this)
- {
- if (native_fd != -1)
- try
- {
- close();
- }
- catch (IOException ex)
- {
- // Nothing we can do about it.
- }
- }
- super.finalize();
- }
-
- public int getNativeFD()
- {
- return native_fd;
+ this.impl = new VMPlainSocketImpl();
}
/**
@@ -155,7 +146,29 @@ public final class PlainSocketImpl extends SocketImpl
*/
public void setOption(int optionId, Object value) throws SocketException
{
- VMPlainSocketImpl.setOption(this, optionId, value);
+ switch (optionId)
+ {
+ case IP_MULTICAST_IF:
+ case IP_MULTICAST_IF2:
+ throw new UnsupportedOperationException("FIXME");
+
+ case IP_MULTICAST_LOOP:
+ case SO_BROADCAST:
+ case SO_KEEPALIVE:
+ case SO_OOBINLINE:
+ case TCP_NODELAY:
+ case IP_TOS:
+ case SO_LINGER:
+ case SO_RCVBUF:
+ case SO_SNDBUF:
+ case SO_TIMEOUT:
+ case SO_REUSEADDR:
+ impl.setOption(optionId, value);
+ return;
+
+ default:
+ throw new SocketException("cannot set option " + optionId);
+ }
}
/**
@@ -171,17 +184,33 @@ public final class PlainSocketImpl extends SocketImpl
*/
public Object getOption(int optionId) throws SocketException
{
- return VMPlainSocketImpl.getOption(this, optionId);
+ if (optionId == SO_BINDADDR)
+ {
+ try
+ {
+ return channel.getVMChannel().getLocalAddress().getAddress();
+ }
+ catch (IOException ioe)
+ {
+ SocketException se = new SocketException();
+ se.initCause(ioe);
+ throw se;
+ }
+ }
+ if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2)
+ throw new UnsupportedOperationException ("can't get option " +
+ optionId + " yet");
+ return impl.getOption(optionId);
}
public void shutdownInput() throws IOException
{
- VMPlainSocketImpl.shutdownInput(this);
+ impl.shutdownInput();
}
public void shutdownOutput() throws IOException
{
- VMPlainSocketImpl.shutdownOutput(this);
+ impl.shutdownOutput();
}
/**
@@ -195,7 +224,11 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected synchronized void create(boolean stream) throws IOException
{
- VMPlainSocketImpl.create(this);
+ channel = new SocketChannelImpl(false);
+ VMChannel vmchannel = channel.getVMChannel();
+ vmchannel.initSocket(stream);
+ channel.configureBlocking(true);
+ impl.getState().setChannelFD(vmchannel.getState());
}
/**
@@ -222,7 +255,7 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected void connect(InetAddress addr, int port) throws IOException
{
- VMPlainSocketImpl.connect(this, addr, port);
+ connect(new InetSocketAddress(addr, port), 0);
}
/**
@@ -236,7 +269,14 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void connect(SocketAddress address, int timeout)
throws IOException
{
- VMPlainSocketImpl.connect(this, address, timeout);
+ if (channel == null)
+ create(true);
+ boolean connected = channel.connect(address, timeout);
+ if (!connected)
+ throw new SocketTimeoutException("connect timed out");
+ InetSocketAddress addr = channel.getVMChannel().getPeerAddress();
+ this.address = addr.getAddress();
+ this.port = addr.getPort();
}
/**
@@ -251,7 +291,10 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void bind(InetAddress addr, int port)
throws IOException
{
- VMPlainSocketImpl.bind(this, addr, port);
+ if (channel == null)
+ create(true);
+ impl.bind(new InetSocketAddress(addr, port));
+ localport = channel.getVMChannel().getLocalAddress().getPort();
}
/**
@@ -267,7 +310,7 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void listen(int queuelen)
throws IOException
{
- VMPlainSocketImpl.listen(this, queuelen);
+ impl.listen(queuelen);
}
/**
@@ -279,7 +322,16 @@ public final class PlainSocketImpl extends SocketImpl
protected synchronized void accept(SocketImpl impl)
throws IOException
{
- VMPlainSocketImpl.accept(this, impl);
+ if (channel == null)
+ create(true);
+ if (!(impl instanceof PlainSocketImpl))
+ throw new IOException("incompatible SocketImpl: "
+ + impl.getClass().getName());
+ PlainSocketImpl that = (PlainSocketImpl) impl;
+ VMChannel c = channel.getVMChannel().accept();
+ that.impl.getState().setChannelFD(c.getState());
+ that.channel = new SocketChannelImpl(c);
+ that.setOption(SO_REUSEADDR, Boolean.TRUE);
}
/**
@@ -292,7 +344,9 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected int available() throws IOException
{
- return VMPlainSocketImpl.available(this);
+ if (channel == null)
+ throw new SocketException("not connected");
+ return channel.getVMChannel().available();
}
/**
@@ -308,65 +362,13 @@ public final class PlainSocketImpl extends SocketImpl
*/
protected void close() throws IOException
{
- VMPlainSocketImpl.close(this);
- }
-
- public void sendUrgentData(int data)
- {
- VMPlainSocketImpl.sendUrgendData(this, data);
- }
-
- /**
- * Internal method used by SocketInputStream for reading data from
- * the connection. Reads up to len bytes of data into the buffer
- * buf starting at offset bytes into the buffer.
- *
- * @return the actual number of bytes read or -1 if end of stream.
- *
- * @throws IOException if an error occurs
- */
- protected int read(byte[] buf, int offset, int len)
- throws IOException
- {
- return VMPlainSocketImpl.read(this, buf, offset, len);
+ if (impl.getState().isValid())
+ impl.close();
}
- /**
- * Internal method used by SocketInputStream for reading data from
- * the connection. Reads and returns one byte of data.
- *
- * @return the read byte
- *
- * @throws IOException if an error occurs
- */
- protected int read()
- throws IOException
+ public void sendUrgentData(int data) throws IOException
{
- return VMPlainSocketImpl.read(this);
- }
-
- /**
- * Internal method used by SocketOuputStream for writing data to
- * the connection. Writes up to len bytes of data from the buffer
- * buf starting at offset bytes into the buffer.
- *
- * @throws IOException If an error occurs
- */
- protected void write(byte[] buf, int offset, int len)
- throws IOException
- {
- VMPlainSocketImpl.write(this, buf, offset, len);
- }
-
- /**
- * Internal method used by SocketOuputStream for writing data to
- * the connection. Writes up one byte to the socket.
- *
- * @throws IOException If an error occurs
- */
- protected void write(int data) throws IOException
- {
- VMPlainSocketImpl.write(this, data);
+ impl.sendUrgentData(data);
}
/**
@@ -400,6 +402,87 @@ public final class PlainSocketImpl extends SocketImpl
return out;
}
+
+ public VMChannel getVMChannel()
+ {
+ if (channel == null)
+ return null;
+ return channel.getVMChannel();
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getInetAddress()
+ */
+ protected InetAddress getInetAddress()
+ {
+ if (channel == null)
+ return null;
+ try
+ {
+ InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
+ if (remote == null)
+ return null;
+ return remote.getAddress();
+ }
+ catch (IOException ioe)
+ {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getLocalPort()
+ */
+ protected int getLocalPort()
+ {
+ if (channel == null)
+ return -1;
+ try
+ {
+ InetSocketAddress local = channel.getVMChannel().getLocalAddress();
+ if (local == null)
+ return -1;
+ return local.getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
+ }
+
+ public InetSocketAddress getLocalAddress()
+ {
+ if (channel == null)
+ return null;
+ try
+ {
+ return channel.getVMChannel().getLocalAddress();
+ }
+ catch (IOException ioe)
+ {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getPort()
+ */
+ protected int getPort()
+ {
+ if (channel == null)
+ return -1;
+ try
+ {
+ InetSocketAddress remote = channel.getVMChannel().getPeerAddress();
+ if (remote == null)
+ return -1;
+ return remote.getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
+ }
/**
* This class contains an implementation of <code>InputStream</code> for
@@ -437,7 +520,23 @@ public final class PlainSocketImpl extends SocketImpl
*/
public int read() throws IOException
{
- return PlainSocketImpl.this.read();
+ if (channel == null)
+ throw new SocketException("not connected");
+ while (true)
+ {
+ try
+ {
+ return channel.getVMChannel().read();
+ }
+ catch (SocketTimeoutException ste)
+ {
+ throw ste;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignore; NIO may throw this; net io shouldn't
+ }
+ }
}
/**
@@ -454,12 +553,24 @@ public final class PlainSocketImpl extends SocketImpl
*/
public int read (byte[] buf, int offset, int len) throws IOException
{
- int bytes_read = PlainSocketImpl.this.read (buf, offset, len);
-
- if (bytes_read == 0)
- return -1;
-
- return bytes_read;
+ if (channel == null)
+ throw new SocketException("not connected");
+ ByteBuffer b = ByteBuffer.wrap(buf, offset, len);
+ while (true)
+ {
+ try
+ {
+ return channel.read(b);
+ }
+ catch (SocketTimeoutException ste)
+ {
+ throw ste;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignored; NIO may throw this; net IO not.
+ }
+ }
}
}
@@ -495,7 +606,20 @@ public final class PlainSocketImpl extends SocketImpl
*/
public void write(int b) throws IOException
{
- PlainSocketImpl.this.write(b);
+ if (channel == null)
+ throw new SocketException("not connected");
+ while (true)
+ {
+ try
+ {
+ channel.getVMChannel().write(b);
+ return;
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignored.
+ }
+ }
}
/**
@@ -510,7 +634,21 @@ public final class PlainSocketImpl extends SocketImpl
*/
public void write (byte[] buf, int offset, int len) throws IOException
{
- PlainSocketImpl.this.write (buf, offset, len);
+ if (channel == null)
+ throw new SocketException("not connected");
+ ByteBuffer b = ByteBuffer.wrap(buf, offset, len);
+ while (b.hasRemaining())
+ {
+ try
+ {
+ if (channel.write(b) == -1)
+ throw new IOException("channel has been closed");
+ }
+ catch (InterruptedIOException iioe)
+ {
+ // Ignored.
+ }
+ }
}
}
}
diff --git a/gnu/java/net/protocol/http/HTTPURLConnection.java b/gnu/java/net/protocol/http/HTTPURLConnection.java
index a46d1204b..cc68a3bac 100644
--- a/gnu/java/net/protocol/http/HTTPURLConnection.java
+++ b/gnu/java/net/protocol/http/HTTPURLConnection.java
@@ -149,6 +149,14 @@ public class HTTPURLConnection
final Credentials creds = (username == null) ? null :
new Credentials (username, password);
+ if ("POST".equals(method))
+ {
+ String contentType = requestHeaders.getValue("Content-Type");
+ if (null == contentType)
+ requestHeaders.addValue("Content-Type",
+ "application/x-www-form-urlencoded");
+ }
+
boolean retry;
do
{
diff --git a/gnu/java/nio/DatagramChannelImpl.java b/gnu/java/nio/DatagramChannelImpl.java
index 4687bf3f5..268ee0a8a 100644
--- a/gnu/java/nio/DatagramChannelImpl.java
+++ b/gnu/java/nio/DatagramChannelImpl.java
@@ -55,8 +55,10 @@ import java.nio.channels.spi.SelectorProvider;
* @author Michael Koch
*/
public final class DatagramChannelImpl extends DatagramChannel
+ implements VMChannelOwner
{
private NIODatagramSocket socket;
+ private VMChannel channel;
/**
* Indicates whether this channel initiated whatever operation
@@ -64,6 +66,16 @@ public final class DatagramChannelImpl extends DatagramChannel
*/
private boolean inChannelOperation;
+ protected DatagramChannelImpl (SelectorProvider provider)
+ throws IOException
+ {
+ super (provider);
+ socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
+ channel = new VMChannel();
+ channel.initSocket(false);
+ configureBlocking(true);
+ }
+
/**
* Indicates whether our datagram socket should ignore whether
* we are set to non-blocking mode. Certain operations on our
@@ -85,14 +97,6 @@ public final class DatagramChannelImpl extends DatagramChannel
inChannelOperation = b;
}
- protected DatagramChannelImpl (SelectorProvider provider)
- throws IOException
- {
- super (provider);
- socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
- configureBlocking(true);
- }
-
public DatagramSocket socket ()
{
return socket;
@@ -101,13 +105,13 @@ public final class DatagramChannelImpl extends DatagramChannel
protected void implCloseSelectableChannel ()
throws IOException
{
- socket.close ();
+ channel.close();
}
protected void implConfigureBlocking (boolean blocking)
throws IOException
{
- socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ channel.setBlocking(blocking);
}
public DatagramChannel connect (SocketAddress remote)
@@ -116,20 +120,34 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isOpen())
throw new ClosedChannelException();
- socket.connect (remote);
+ try
+ {
+ channel.connect((InetSocketAddress) remote, 0);
+ }
+ catch (ClassCastException cce)
+ {
+ throw new IOException("unsupported socked address type");
+ }
return this;
}
public DatagramChannel disconnect ()
throws IOException
{
- socket.disconnect ();
+ channel.disconnect();
return this;
}
- public boolean isConnected ()
+ public boolean isConnected()
{
- return socket.isConnected ();
+ try
+ {
+ return channel.getPeerAddress() != null;
+ }
+ catch (IOException ioe)
+ {
+ return false;
+ }
}
public int write (ByteBuffer src)
@@ -138,7 +156,7 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isConnected ())
throw new NotYetConnectedException ();
- return send (src, socket.getRemoteSocketAddress());
+ return channel.write(src);
}
public long write (ByteBuffer[] srcs, int offset, int length)
@@ -152,13 +170,11 @@ public final class DatagramChannelImpl extends DatagramChannel
|| (length < 0)
|| (length > (srcs.length - offset)))
throw new IndexOutOfBoundsException();
-
- long result = 0;
-
- for (int index = offset; index < offset + length; index++)
- result += write (srcs [index]);
- return result;
+ /* We are connected, meaning we will write these bytes to
+ * the host we connected to, so we don't need to explicitly
+ * give the host. */
+ return channel.writeGathering(srcs, offset, length);
}
public int read (ByteBuffer dst)
@@ -167,9 +183,7 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isConnected ())
throw new NotYetConnectedException ();
- int remaining = dst.remaining();
- receive (dst);
- return remaining - dst.remaining();
+ return channel.read(dst);
}
public long read (ByteBuffer[] dsts, int offset, int length)
@@ -184,12 +198,8 @@ public final class DatagramChannelImpl extends DatagramChannel
|| (length > (dsts.length - offset)))
throw new IndexOutOfBoundsException();
- long result = 0;
-
- for (int index = offset; index < offset + length; index++)
- result += read (dsts [index]);
-
- return result;
+ /* Likewise, see the comment int write above. */
+ return channel.readScattering(dsts, offset, length);
}
public SocketAddress receive (ByteBuffer dst)
@@ -200,49 +210,12 @@ public final class DatagramChannelImpl extends DatagramChannel
try
{
- DatagramPacket packet;
- int len = dst.remaining();
-
- if (dst.hasArray())
- {
- packet = new DatagramPacket (dst.array(),
- dst.arrayOffset() + dst.position(),
- len);
- }
- else
- {
- packet = new DatagramPacket (new byte [len], len);
- }
-
- boolean completed = false;
-
- try
- {
- begin();
- setInChannelOperation(true);
- socket.receive (packet);
- completed = true;
- }
- finally
- {
- end (completed);
- setInChannelOperation(false);
- }
-
- if (!dst.hasArray())
- {
- dst.put (packet.getData(), packet.getOffset(), packet.getLength());
- }
- else
- {
- dst.position (dst.position() + packet.getLength());
- }
-
- return packet.getSocketAddress();
+ begin();
+ return channel.receive(dst);
}
- catch (SocketTimeoutException e)
+ finally
{
- return null;
+ end(true);
}
}
@@ -252,46 +225,18 @@ public final class DatagramChannelImpl extends DatagramChannel
if (!isOpen())
throw new ClosedChannelException();
- if (target instanceof InetSocketAddress
- && ((InetSocketAddress) target).isUnresolved())
- throw new IOException("Target address not resolved");
-
- byte[] buffer;
- int offset = 0;
- int len = src.remaining();
+ if (!(target instanceof InetSocketAddress))
+ throw new IOException("can only send to inet socket addresses");
- if (src.hasArray())
- {
- buffer = src.array();
- offset = src.arrayOffset() + src.position();
- }
- else
- {
- buffer = new byte [len];
- src.get (buffer);
- }
-
- DatagramPacket packet = new DatagramPacket (buffer, offset, len, target);
-
- boolean completed = false;
- try
- {
- begin();
- setInChannelOperation(true);
- socket.send(packet);
- completed = true;
- }
- finally
- {
- end (completed);
- setInChannelOperation(false);
- }
-
- if (src.hasArray())
- {
- src.position (src.position() + len);
- }
+ InetSocketAddress dst = (InetSocketAddress) target;
+ if (dst.isUnresolved())
+ throw new IOException("Target address not resolved");
- return len;
+ return channel.send(src, dst);
+ }
+
+ public VMChannel getVMChannel()
+ {
+ return channel;
}
}
diff --git a/gnu/java/nio/DatagramChannelSelectionKey.java b/gnu/java/nio/DatagramChannelSelectionKey.java
index 698e07e34..f192e5002 100644
--- a/gnu/java/nio/DatagramChannelSelectionKey.java
+++ b/gnu/java/nio/DatagramChannelSelectionKey.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
import java.nio.channels.spi.AbstractSelectableChannel;
/**
@@ -52,10 +53,16 @@ public final class DatagramChannelSelectionKey
super (channel, selector);
}
+ // FIXME don't use file descriptor integers
public int getNativeFD()
{
- NIODatagramSocket socket =
- (NIODatagramSocket) ((DatagramChannelImpl) ch).socket();
- return socket.getPlainDatagramSocketImpl().getNativeFD();
+ try
+ {
+ return ((DatagramChannelImpl) ch).getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalStateException(ioe);
+ }
}
}
diff --git a/gnu/java/nio/EpollSelectionKeyImpl.java b/gnu/java/nio/EpollSelectionKeyImpl.java
new file mode 100644
index 000000000..11113f397
--- /dev/null
+++ b/gnu/java/nio/EpollSelectionKeyImpl.java
@@ -0,0 +1,122 @@
+/* EpollSelectionKeyImpl.java -- selection key for the epoll selector.
+ 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 gnu.java.nio;
+
+import java.io.IOException;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectionKey;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class EpollSelectionKeyImpl extends AbstractSelectionKey
+{
+ final int fd;
+ private final EpollSelectorImpl selector;
+ private final SelectableChannel channel;
+ int interestOps;
+ int selectedOps;
+ int key;
+ boolean valid;
+ boolean cancelled;
+
+ EpollSelectionKeyImpl(EpollSelectorImpl selector,
+ SelectableChannel channel, int fd)
+ {
+ this.selector = selector;
+ this.channel = channel;
+ this.fd = fd;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#channel()
+ */
+ public SelectableChannel channel()
+ {
+ return channel;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps()
+ */
+ public int interestOps()
+ {
+ return interestOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps(int)
+ */
+ public SelectionKey interestOps(int ops)
+ {
+ if (cancelled)
+ throw new CancelledKeyException();
+ if ((ops & ~(channel.validOps())) != 0)
+ throw new IllegalArgumentException("unsupported channel ops");
+ try
+ {
+ selector.epoll_modify(this, ops);
+ interestOps = ops;
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalArgumentException(ioe);
+ }
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#readyOps()
+ */
+ public int readyOps()
+ {
+ return selectedOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#selector()
+ */
+ public Selector selector()
+ {
+ return selector;
+ }
+}
diff --git a/gnu/java/nio/EpollSelectorImpl.java b/gnu/java/nio/EpollSelectorImpl.java
new file mode 100644
index 000000000..2b3c9bbb1
--- /dev/null
+++ b/gnu/java/nio/EpollSelectorImpl.java
@@ -0,0 +1,399 @@
+/* EpollSelectorImpl.java -- selector implementation using epoll
+ 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 gnu.java.nio;
+
+import gnu.classpath.Configuration;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * An implementation of {@link Selector} that uses the epoll event
+ * notification mechanism on GNU/Linux.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class EpollSelectorImpl extends AbstractSelector
+{
+ // XXX is this reasonable? Does it matter?
+ private static final int DEFAULT_EPOLL_SIZE = 128;
+ private static final int sizeof_struct_epoll_event;
+
+ private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT;
+ private static final int OP_CONNECT = SelectionKey.OP_CONNECT;
+ private static final int OP_READ = SelectionKey.OP_READ;
+ private static final int OP_WRITE = SelectionKey.OP_WRITE;
+
+ /** our epoll file descriptor. */
+ private int epoll_fd;
+
+ private final HashMap keys;
+ private Set selectedKeys;
+ private Thread waitingThread;
+ private ByteBuffer events;
+
+ private static final int INITIAL_CAPACITY;
+ private static final int MAX_DOUBLING_CAPACITY;
+ private static final int CAPACITY_INCREMENT;
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ System.loadLibrary("javanio");
+
+ if (epoll_supported())
+ sizeof_struct_epoll_event = sizeof_struct();
+ else
+ sizeof_struct_epoll_event = -1;
+
+ INITIAL_CAPACITY = 64 * sizeof_struct_epoll_event;
+ MAX_DOUBLING_CAPACITY = 1024 * sizeof_struct_epoll_event;
+ CAPACITY_INCREMENT = 128 * sizeof_struct_epoll_event;
+ }
+
+ public EpollSelectorImpl(SelectorProvider provider)
+ throws IOException
+ {
+ super(provider);
+ epoll_fd = epoll_create(DEFAULT_EPOLL_SIZE);
+ keys = new HashMap();
+ selectedKeys = null;
+ events = ByteBuffer.allocateDirect(INITIAL_CAPACITY);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#keys()
+ */
+ public Set keys()
+ {
+ return new HashSet(keys.values());
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select()
+ */
+ public int select() throws IOException
+ {
+ return doSelect(-1);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select(long)
+ */
+ public int select(long timeout) throws IOException
+ {
+ if (timeout > Integer.MAX_VALUE)
+ throw new IllegalArgumentException("timeout is too large");
+ if (timeout < 0)
+ throw new IllegalArgumentException("invalid timeout");
+ return doSelect((int) timeout);
+ }
+
+ private int doSelect(int timeout) throws IOException
+ {
+ synchronized (keys)
+ {
+ Set cancelledKeys = cancelledKeys();
+ synchronized (cancelledKeys)
+ {
+ for (Iterator it = cancelledKeys.iterator(); it.hasNext(); )
+ {
+ EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next();
+ epoll_delete(epoll_fd, key.fd);
+ key.valid = false;
+ keys.remove(Integer.valueOf(key.fd));
+ it.remove();
+ deregister(key);
+ }
+
+ // Clear out closed channels. The fds are removed from the epoll
+ // fd when closed, so there is no need to remove them manually.
+ for (Iterator it = keys.values().iterator(); it.hasNext(); )
+ {
+ EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next();
+ SelectableChannel ch = key.channel();
+ if (ch instanceof VMChannelOwner)
+ {
+ if (!((VMChannelOwner) ch).getVMChannel().getState().isValid())
+ it.remove();
+ }
+ }
+
+ // Don't bother if we have nothing to select.
+ if (keys.isEmpty())
+ return 0;
+
+ int ret;
+ try
+ {
+ begin();
+ waitingThread = Thread.currentThread();
+ ret = epoll_wait(epoll_fd, events, keys.size(), timeout);
+ }
+ finally
+ {
+ Thread.interrupted();
+ waitingThread = null;
+ end();
+ }
+
+ HashSet s = new HashSet(ret);
+ for (int i = 0; i < ret; i++)
+ {
+ events.position(i * sizeof_struct_epoll_event);
+ ByteBuffer b = events.slice();
+ int fd = selected_fd(b);
+ EpollSelectionKeyImpl key
+ = (EpollSelectionKeyImpl) keys.get(Integer.valueOf(fd));
+ if (key == null)
+ throw new IOException("fd was selected, but no key found");
+ key.selectedOps = selected_ops(b) & key.interestOps;
+ s.add(key);
+ }
+
+ reallocateBuffer();
+
+ selectedKeys = s;
+ return ret;
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectedKeys()
+ */
+ public Set selectedKeys()
+ {
+ if (selectedKeys == null)
+ return Collections.EMPTY_SET;
+ return selectedKeys;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectNow()
+ */
+ public int selectNow() throws IOException
+ {
+ return doSelect(0);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#wakeup()
+ */
+ public Selector wakeup()
+ {
+ try
+ {
+ waitingThread.interrupt();
+ }
+ catch (NullPointerException npe)
+ {
+ // Ignored, thrown if we are not in a blocking op.
+ }
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.spi.AbstractSelector#implCloseSelector()
+ */
+ protected void implCloseSelector() throws IOException
+ {
+ VMChannel.close(epoll_fd);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.spi.AbstractSelector#register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object)
+ */
+ protected SelectionKey register(AbstractSelectableChannel ch, int ops, Object att)
+ {
+ if (!(ch instanceof VMChannelOwner))
+ throw new IllegalArgumentException("unsupported channel type");
+
+ VMChannel channel = ((VMChannelOwner) ch).getVMChannel();
+ try
+ {
+ int native_fd = channel.getState().getNativeFD();
+ synchronized (keys)
+ {
+ if (keys.containsKey(Integer.valueOf(native_fd)))
+ throw new IllegalArgumentException("channel already registered");
+ EpollSelectionKeyImpl result =
+ new EpollSelectionKeyImpl(this, ch, native_fd);
+ if ((ops & ~(ch.validOps())) != 0)
+ throw new IllegalArgumentException("invalid ops for channel");
+ result.interestOps = ops;
+ result.selectedOps = 0;
+ result.valid = true;
+ result.attach(att);
+ result.key = System.identityHashCode(result);
+ epoll_add(epoll_fd, result.fd, ops);
+ keys.put(Integer.valueOf(native_fd), result);
+ reallocateBuffer();
+ return result;
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalArgumentException(ioe);
+ }
+ }
+
+ private void reallocateBuffer()
+ {
+ // Ensure we have enough space for all potential events that may be
+ // returned.
+ if (events.capacity() < keys.size() * sizeof_struct_epoll_event)
+ {
+ int cap = events.capacity();
+ if (cap < MAX_DOUBLING_CAPACITY)
+ cap <<= 1;
+ else
+ cap += CAPACITY_INCREMENT;
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ // Ensure that the events buffer is not too large, given the number of
+ // events registered.
+ else if (events.capacity() > keys.size() * sizeof_struct_epoll_event * 2 + 1
+ && events.capacity() > INITIAL_CAPACITY)
+ {
+ int cap = events.capacity() >>> 1;
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ }
+
+ void epoll_modify(EpollSelectionKeyImpl key, int ops) throws IOException
+ {
+ epoll_modify(epoll_fd, key.fd, ops);
+ }
+
+ /**
+ * Tell if epoll is supported by this system, and support was compiled in.
+ *
+ * @return True if this system supports event notification with epoll.
+ */
+ public static native boolean epoll_supported();
+
+
+ /**
+ * Returns the size of `struct epoll_event'.
+ *
+ * @return The size of `struct epoll_event'.
+ */
+ private static native int sizeof_struct();
+
+
+ /**
+ * Open a new epoll file descriptor.
+ *
+ * @param size The size hint for the new epoll descriptor.
+ * @return The new file descriptor integer.
+ * @throws IOException If allocating a new epoll descriptor fails.
+ */
+ private static native int epoll_create(int size) throws IOException;
+
+ /**
+ * Add a file descriptor to this selector.
+ *
+ * @param efd The epoll file descriptor.
+ * @param fd The file descriptor to add (or modify).
+ * @param ops The interest opts.
+ */
+ private static native void epoll_add(int efd, int fd, int ops)
+ throws IOException;
+
+ /**
+ * Modify the interest ops of the key selecting for the given FD.
+ *
+ * @param efd The epoll file descriptor.
+ * @param fd The file descriptor to modify.
+ * @param ops The ops.
+ * @throws IOException
+ */
+ private static native void epoll_modify(int efd, int fd, int ops)
+ throws IOException;
+
+ /**
+ * Remove a file descriptor from this selector.
+ *
+ * @param efd The epoll file descriptor.
+ * @param fd The file descriptor.
+ * @throws IOException
+ */
+ private static native void epoll_delete(int efd, int fd) throws IOException;
+
+ /**
+ * Select events.
+ *
+ * @param efd The epoll file descriptor.
+ * @param state The buffer to hold selected events.
+ * @param n The number of events that may be put in `state'.
+ * @param timeout The timeout.
+ * @return The number of events selected.
+ * @throws IOException
+ */
+ private static native int epoll_wait(int efd, ByteBuffer state, int n, int timeout)
+ throws IOException;
+
+ /**
+ * Fetch the fd value from a selected struct epoll_event.
+ *
+ * @param struct The direct buffer holding the struct.
+ * @return The fd value.
+ */
+ private static native int selected_fd(ByteBuffer struct);
+
+ /**
+ * Fetch the enabled operations from a selected struct epoll_event.
+ *
+ * @param struct The direct buffer holding the struct.
+ * @return The selected operations.
+ */
+ private static native int selected_ops(ByteBuffer struct);
+}
diff --git a/gnu/java/nio/channels/FileChannelImpl.java b/gnu/java/nio/FileChannelImpl.java
index ed439e141..419124050 100644
--- a/gnu/java/nio/channels/FileChannelImpl.java
+++ b/gnu/java/nio/FileChannelImpl.java
@@ -36,7 +36,7 @@ obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
-package gnu.java.nio.channels;
+package gnu.java.nio;
import gnu.classpath.Configuration;
import gnu.java.nio.FileLockImpl;
@@ -74,11 +74,11 @@ public final class FileChannelImpl extends FileChannel
public static final int SYNC = 16;
public static final int DSYNC = 32;
- public static FileChannelImpl in;
- public static FileChannelImpl out;
- public static FileChannelImpl err;
+ public static final FileChannelImpl in;
+ public static final FileChannelImpl out;
+ public static final FileChannelImpl err;
- private static native void init();
+ //private static native void init();
static
{
@@ -87,22 +87,45 @@ public final class FileChannelImpl extends FileChannel
System.loadLibrary("javanio");
}
- init();
+ //init();
- in = new FileChannelImpl(0, READ);
- out = new FileChannelImpl(1, WRITE);
- err = new FileChannelImpl(2, WRITE);
+ FileChannelImpl ch = null;
+ try
+ {
+ ch = new FileChannelImpl(VMChannel.getStdin(), READ);
+ }
+ catch (IOException ioe)
+ {
+ throw new Error(ioe);
+ }
+ in = ch;
+
+ ch = null;
+ try
+ {
+ ch = new FileChannelImpl(VMChannel.getStdout(), WRITE);
+ }
+ catch (IOException ioe)
+ {
+ throw new Error(ioe);
+ }
+ out = ch;
+
+ ch = null;
+ try
+ {
+ ch = new FileChannelImpl(VMChannel.getStderr(), WRITE);
+ }
+ catch (IOException ioe)
+ {
+ throw new Error(ioe);
+ }
+ err = ch;
}
/**
* This is the actual native file descriptor value
*/
- // System's notion of file descriptor. It might seem redundant to
- // initialize this given that it is reassigned in the constructors.
- // However, this is necessary because if open() throws an exception
- // we want to make sure this has the value -1. This is the most
- // efficient way to accomplish that.
- private int fd = -1;
private VMChannel ch;
private int mode;
@@ -113,19 +136,19 @@ public final class FileChannelImpl extends FileChannel
/* This is a static factory method, so that VM implementors can decide
* substitute subclasses of FileChannelImpl. */
public static FileChannelImpl create(File file, int mode)
- throws FileNotFoundException
+ throws IOException
{
return new FileChannelImpl(file, mode);
}
private FileChannelImpl(File file, int mode)
- throws FileNotFoundException
+ throws IOException
{
String path = file.getPath();
description = path;
- fd = open (path, mode);
this.mode = mode;
- this.ch = VMChannel.getVMChannel(this);
+ this.ch = new VMChannel();
+ ch.openFile(path, mode);
// First open the file and then check if it is a a directory
// to avoid race condition.
@@ -133,11 +156,11 @@ public final class FileChannelImpl extends FileChannel
{
try
{
- close();
+ close();
}
catch (IOException e)
{
- /* ignore it */
+ /* ignore it */
}
throw new FileNotFoundException(description + " is a directory");
@@ -153,49 +176,59 @@ public final class FileChannelImpl extends FileChannel
*
* @param mode READ or WRITE
*/
- FileChannelImpl (int fd, int mode)
+ FileChannelImpl (VMChannel ch, int mode)
{
- this.fd = fd;
this.mode = mode;
- this.description = "descriptor(" + fd + ")";
- this.ch = VMChannel.getVMChannel(this);
+ this.description = "descriptor(" + ch.getState() + ")";
+ this.ch = ch;
}
- private native int open (String path, int mode) throws FileNotFoundException;
+ public int available() throws IOException
+ {
+ return ch.available();
+ }
+
+ private long implPosition() throws IOException
+ {
+ return ch.position();
+ }
- public native int available () throws IOException;
- private native long implPosition () throws IOException;
- private native void seek (long newPosition) throws IOException;
- private native void implTruncate (long size) throws IOException;
+ private void seek(long newPosition) throws IOException
+ {
+ ch.seek(newPosition);
+ }
+
+ private void implTruncate(long size) throws IOException
+ {
+ ch.truncate(size);
+ }
- public native void unlock (long pos, long len) throws IOException;
+ public void unlock(long pos, long len) throws IOException
+ {
+ ch.unlock(pos, len);
+ }
- public native long size () throws IOException;
+ public long size () throws IOException
+ {
+ return ch.size();
+ }
- protected native void implCloseChannel() throws IOException;
+ protected void implCloseChannel() throws IOException
+ {
+ ch.close();
+ }
/**
* Makes sure the Channel is properly closed.
*/
protected void finalize() throws IOException
{
- if (fd != -1)
+ if (ch.getState().isValid())
close();
}
public int read (ByteBuffer dst) throws IOException
{
- /*
- int result;
- byte[] buffer = new byte [dst.remaining ()];
-
- result = read (buffer, 0, buffer.length);
-
- if (result > 0)
- dst.put (buffer, 0, result);
-
- return result;
- */
return ch.read(dst);
}
@@ -212,11 +245,10 @@ public final class FileChannelImpl extends FileChannel
return result;
}
- public native int read ()
- throws IOException;
-
- public native int read (byte[] buffer, int offset, int length)
- throws IOException;
+ public int read() throws IOException
+ {
+ return ch.read();
+ }
public long read (ByteBuffer[] dsts, int offset, int length)
throws IOException
@@ -252,19 +284,16 @@ public final class FileChannelImpl extends FileChannel
return result;
}
- public native void write (byte[] buffer, int offset, int length)
- throws IOException;
-
- public native void write (int b) throws IOException;
+ public void write (int b) throws IOException
+ {
+ ch.write(b);
+ }
public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException
{
return ch.writeGathering(srcs, offset, length);
}
-
- public native MappedByteBuffer mapImpl (char mode, long position, int size)
- throws IOException;
public MappedByteBuffer map (FileChannel.MapMode mode,
long position, long size)
@@ -291,7 +320,7 @@ public final class FileChannelImpl extends FileChannel
if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
throw new IllegalArgumentException ("position: " + position
+ ", size: " + size);
- return mapImpl(nmode, position, (int) size);
+ return ch.map(nmode, position, (int) size);
}
/**
@@ -302,11 +331,9 @@ public final class FileChannelImpl extends FileChannel
if (!isOpen ())
throw new ClosedChannelException ();
- force ();
+ ch.flush(metaData);
}
- private native void force ();
-
// like transferTo, but with a count of less than 2Gbytes
private int smallTransferTo (long position, int count,
WritableByteChannel target)
@@ -453,7 +480,7 @@ public final class FileChannelImpl extends FileChannel
try
{
begin();
- boolean lockable = lock(position, size, shared, false);
+ boolean lockable = ch.lock(position, size, shared, false);
completed = true;
return (lockable
? new FileLockImpl(this, position, size, shared)
@@ -464,14 +491,6 @@ public final class FileChannelImpl extends FileChannel
end(completed);
}
}
-
- /** Try to acquire a lock at the given position and size.
- * On success return true.
- * If wait as specified, block until we can get it.
- * Otherwise return false.
- */
- private native boolean lock(long position, long size,
- boolean shared, boolean wait) throws IOException;
public FileLock lock (long position, long size, boolean shared)
throws IOException
@@ -481,7 +500,7 @@ public final class FileChannelImpl extends FileChannel
boolean completed = false;
try
{
- boolean lockable = lock(position, size, shared, true);
+ boolean lockable = ch.lock(position, size, shared, true);
completed = true;
return (lockable
? new FileLockImpl(this, position, size, shared)
@@ -537,17 +556,17 @@ public final class FileChannelImpl extends FileChannel
public String toString()
{
- return (this.getClass()
- + "[fd=" + fd
- + ",mode=" + mode + ","
- + description + "]");
+ return (super.toString()
+ + "[ fd: " + ch.getState()
+ + "; mode: " + Integer.toOctalString(mode)
+ + "; " + description + " ]");
}
/**
* @return The native file descriptor.
- */
+ * /
public int getNativeFD()
{
return fd;
- }
+ }*/
}
diff --git a/gnu/java/nio/FileLockImpl.java b/gnu/java/nio/FileLockImpl.java
index 673ca2522..768906ce9 100644
--- a/gnu/java/nio/FileLockImpl.java
+++ b/gnu/java/nio/FileLockImpl.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package gnu.java.nio;
-import gnu.java.nio.channels.FileChannelImpl;
-
import java.io.IOException;
import java.nio.channels.FileLock;
diff --git a/gnu/java/nio/KqueueSelectionKeyImpl.java b/gnu/java/nio/KqueueSelectionKeyImpl.java
new file mode 100644
index 000000000..2f93c50cc
--- /dev/null
+++ b/gnu/java/nio/KqueueSelectionKeyImpl.java
@@ -0,0 +1,189 @@
+/* KqueueSelectionKeyImpl.java -- selection key for kqueue/kevent.
+ 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 gnu.java.nio;
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectionKey;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class KqueueSelectionKeyImpl extends AbstractSelectionKey
+{
+ int interestOps;
+ int readyOps;
+ int activeOps = 0;
+ int key;
+ int fd;
+
+ /** The selector we were created for. */
+ private final KqueueSelectorImpl selector;
+
+ /** The channel we are attached to. */
+ private final SelectableChannel channel;
+
+ private final VMChannelOwner natChannel;
+
+ public KqueueSelectionKeyImpl(KqueueSelectorImpl selector,
+ SelectableChannel channel)
+ {
+ this.selector = selector;
+ this.channel = channel;
+ natChannel = (VMChannelOwner) channel;
+ interestOps = 0;
+ readyOps = 0;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#channel()
+ */
+ //@Override
+ public SelectableChannel channel()
+ {
+ return channel;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps()
+ */
+ //@Override
+ public int interestOps()
+ {
+ return interestOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#interestOps(int)
+ */
+ //@Override
+ public SelectionKey interestOps(int ops)
+ {
+ if (!isValid())
+ throw new IllegalStateException("key is invalid");
+ if ((ops & ~channel.validOps()) != 0)
+ throw new IllegalArgumentException("channel does not support all operations");
+
+ selector.setInterestOps(this, ops);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#readyOps()
+ */
+ //@Override
+ public int readyOps()
+ {
+ return readyOps;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.SelectionKey#selector()
+ */
+ //@Override
+ public Selector selector()
+ {
+ return selector;
+ }
+
+ public String toString()
+ {
+ if (!isValid())
+ return super.toString() + " [ fd: " + fd + " <<invalid>> ]";
+ return super.toString() + " [ fd: " + fd + " interest ops: {"
+ + ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "")
+ + ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "")
+ + ((interestOps & OP_READ) != 0 ? " OP_READ" : "")
+ + ((interestOps & OP_WRITE) != 0 ? " OP_WRITE" : "")
+ + " }; ready ops: {"
+ + ((readyOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "")
+ + ((readyOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "")
+ + ((readyOps & OP_READ) != 0 ? " OP_READ" : "")
+ + ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "")
+ + " } ]";
+ }
+
+ public int hashCode()
+ {
+ return fd;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof KqueueSelectionKeyImpl))
+ return false;
+ KqueueSelectionKeyImpl that = (KqueueSelectionKeyImpl) o;
+ return that.fd == this.fd && that.channel.equals(this.channel);
+ }
+
+
+ boolean isReadActive()
+ {
+ return (activeOps & (OP_READ | OP_ACCEPT)) != 0;
+ }
+
+ boolean isReadInterested()
+ {
+ return (interestOps & (OP_READ | OP_ACCEPT)) != 0;
+ }
+
+ boolean isWriteActive()
+ {
+ return (activeOps & (OP_WRITE | OP_CONNECT)) != 0;
+ }
+
+ boolean isWriteInterested()
+ {
+ return (interestOps & (OP_WRITE | OP_CONNECT)) != 0;
+ }
+
+ boolean needCommitRead()
+ {
+ return isReadActive() == (!isReadInterested());
+ }
+
+ boolean needCommitWrite()
+ {
+ return isWriteActive() == (!isWriteInterested());
+ }
+}
diff --git a/gnu/java/nio/KqueueSelectorImpl.java b/gnu/java/nio/KqueueSelectorImpl.java
new file mode 100644
index 000000000..eed86119c
--- /dev/null
+++ b/gnu/java/nio/KqueueSelectorImpl.java
@@ -0,0 +1,524 @@
+/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification.
+ 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 gnu.java.nio;
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A {@link Selector} implementation that uses the <code>kqueue</code>
+ * event notification facility.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class KqueueSelectorImpl extends AbstractSelector
+{
+ private static final int sizeof_struct_kevent;
+ private static final int MAX_DOUBLING_CAPACITY = 16384;
+ private static final int CAP_INCREMENT = 1024;
+ private static final int INITIAL_CAPACITY;
+
+ static
+ {
+ try
+ {
+ System.loadLibrary("javanio");
+ }
+ catch (Exception x)
+ {
+ x.printStackTrace();
+ }
+
+ if (kqueue_supported ())
+ sizeof_struct_kevent = sizeof_struct_kevent();
+ else
+ sizeof_struct_kevent = -1;
+ INITIAL_CAPACITY = 16 * sizeof_struct_kevent;
+ }
+
+ /**
+ * Tell if kqueue-based selectors are supported on this system.
+ *
+ * @return True if this system has kqueue support, and support for it was
+ * compiled in to Classpath.
+ */
+ public static native boolean kqueue_supported();
+
+ /* Our native file descriptor. */
+ private int kq;
+
+ private HashMap/*<Integer,KqueueSelectionKeyImpl>*/ keys;
+ private HashSet/*<KqueueSelectionKeyImpl>*/ selected;
+ private Thread blockedThread;
+ private ByteBuffer events;
+
+ private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT;
+ private static final int OP_CONNECT = SelectionKey.OP_CONNECT;
+ private static final int OP_READ = SelectionKey.OP_READ;
+ private static final int OP_WRITE = SelectionKey.OP_WRITE;
+
+ public KqueueSelectorImpl(SelectorProvider provider) throws IOException
+ {
+ super(provider);
+ kq = implOpen();
+ keys = new HashMap/*<KqueueSelectionKeyImpl>*/();
+ events = ByteBuffer.allocateDirect(INITIAL_CAPACITY);
+ }
+
+ protected void implCloseSelector() throws IOException
+ {
+ implClose(kq);
+ kq = -1;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#keys()
+ */
+ public Set keys()
+ {
+ if (!isOpen())
+ throw new ClosedSelectorException();
+
+ return new HashSet(keys.values());
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select()
+ */
+ public int select() throws IOException
+ {
+ return doSelect(-1);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#select(long)
+ */
+ public int select(long timeout) throws IOException
+ {
+ if (timeout == 0)
+ timeout = -1;
+ return doSelect(timeout);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectedKeys()
+ */
+ public Set selectedKeys()
+ {
+ if (!isOpen())
+ throw new ClosedSelectorException();
+
+ return selected;
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#selectNow()
+ */
+ public int selectNow() throws IOException
+ {
+ return doSelect(0);
+ }
+
+ /* (non-Javadoc)
+ * @see java.nio.channels.Selector#wakeup()
+ */
+ public Selector wakeup()
+ {
+ if (blockedThread != null)
+ blockedThread.interrupt();
+ return this;
+ }
+
+ public String toString()
+ {
+ return super.toString() + " [ fd: " + kq + " ]";
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof KqueueSelectorImpl))
+ return false;
+
+ return ((KqueueSelectorImpl) o).kq == kq;
+ }
+
+ int doSelect(long timeout) throws IOException
+ {
+ Set cancelled = cancelledKeys();
+ synchronized (cancelled)
+ {
+ synchronized (keys)
+ {
+ for (Iterator it = cancelled.iterator(); it.hasNext(); )
+ {
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+ key.interestOps = 0;
+ }
+
+ int events_size = (2 * sizeof_struct_kevent) * keys.size();
+ int num_events = 0;
+
+ for (Iterator it = keys.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry e = (Map.Entry) it.next();
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue();
+
+ SelectableChannel ch = key.channel();
+ if (ch instanceof VMChannelOwner)
+ {
+ if (!((VMChannelOwner) ch).getVMChannel().getState().isValid())
+ {
+ // closed channel; removed from kqueue automatically.
+ it.remove();
+ continue;
+ }
+ }
+
+ // If this key is registering a read filter, add it to the buffer.
+ if (key.needCommitRead())
+ {
+ kevent_set(events, num_events, key.fd,
+ key.interestOps & (OP_READ | OP_ACCEPT),
+ key.activeOps & (OP_READ | OP_ACCEPT), key.key);
+ num_events++;
+ }
+
+ // If this key is registering a write filter, add it to the buffer.
+ if (key.needCommitWrite())
+ {
+ kevent_set(events, num_events, key.fd,
+ key.interestOps & (OP_WRITE | OP_CONNECT),
+ key.activeOps & (OP_WRITE | OP_CONNECT), key.key);
+ num_events++;
+ }
+ }
+ events.rewind().limit(events.capacity());
+
+ //System.out.println("dump of keys to select:");
+ //dump_selection_keys(events.duplicate());
+
+ int n = 0;
+ try
+ {
+ //System.out.println("[" + kq + "] kevent enter selecting from " + keys.size());
+ begin();
+ blockedThread = Thread.currentThread();
+ if (blockedThread.isInterrupted())
+ timeout = 0;
+ n = kevent(kq, events, num_events,
+ events.capacity() / sizeof_struct_kevent, timeout);
+ }
+ finally
+ {
+ end();
+ blockedThread = null;
+ Thread.interrupted();
+ //System.out.println("[" + kq + "kevent exit selected " + n);
+ }
+
+ //System.out.println("dump of keys selected:");
+ //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * sizeof_struct_kevent));
+
+ // Commit the operations we've just added in the call to kevent.
+ for (Iterator it = keys.values().iterator(); it.hasNext(); )
+ {
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+ key.activeOps = key.interestOps;
+ }
+
+ selected = new HashSet/*<KqueueSelectionKeyImpl>*/(n);
+ int x = 0;
+ for (int i = 0; i < n; i++)
+ {
+ events.position(x).limit(x + sizeof_struct_kevent);
+ x += sizeof_struct_kevent;
+ int y = fetch_key(events.slice());
+ KqueueSelectionKeyImpl key =
+ (KqueueSelectionKeyImpl) keys.get(new Integer(y));
+
+ if (key == null)
+ {
+ System.out.println("WARNING! no key found for selected key " + y);
+ continue;
+ }
+ // Keys that have been cancelled may be returned here; don't
+ // add them to the selected set.
+ if (!key.isValid())
+ continue;
+ key.readyOps = ready_ops(events.slice(), key.interestOps);
+ selected.add(key);
+ }
+
+ // Finally, remove the cancelled keys.
+ for (Iterator it = cancelled.iterator(); it.hasNext(); )
+ {
+ KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+ keys.remove(new Integer(key.key));
+ deregister(key);
+ it.remove();
+ }
+
+ reallocateBuffer();
+
+ return selected.size();
+ }
+ }
+ }
+
+ protected SelectionKey register(AbstractSelectableChannel channel,
+ int interestOps,
+ Object attachment)
+ {
+ int native_fd = -1;
+ try
+ {
+ if (channel instanceof VMChannelOwner)
+ native_fd = ((VMChannelOwner) channel).getVMChannel()
+ .getState().getNativeFD();
+ else
+ throw new IllegalArgumentException("cannot handle channel type " +
+ channel.getClass().getName());
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalArgumentException("channel is closed or invalid");
+ }
+
+ KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel);
+ result.interestOps = interestOps;
+ result.attach(attachment);
+ result.fd = native_fd;
+ result.key = System.identityHashCode(result);
+ synchronized (keys)
+ {
+ while (keys.containsKey(new Integer(result.key)))
+ result.key++;
+ keys.put(new Integer(result.key), result);
+ reallocateBuffer();
+ }
+ return result;
+ }
+
+ void setInterestOps(KqueueSelectionKeyImpl key, int ops)
+ {
+ synchronized (keys)
+ {
+ key.interestOps = ops;
+ }
+ }
+
+ /**
+ * Reallocate the events buffer. This is the destination buffer for
+ * events returned by kevent. This method will:
+ *
+ * * Grow the buffer if there is insufficent space for all registered
+ * events.
+ * * Shrink the buffer if it is more than twice the size needed.
+ *
+ */
+ private void reallocateBuffer()
+ {
+ synchronized (keys)
+ {
+ if (events.capacity() < (2 * sizeof_struct_kevent) * keys.size())
+ {
+ int cap = events.capacity();
+ if (cap >= MAX_DOUBLING_CAPACITY)
+ cap += CAP_INCREMENT;
+ else
+ cap = cap << 1;
+
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ else if (events.capacity() > 4 * (sizeof_struct_kevent) * keys.size() + 1
+ && events.capacity() > INITIAL_CAPACITY)
+ {
+ int cap = events.capacity();
+ cap = cap >>> 1;
+ events = ByteBuffer.allocateDirect(cap);
+ }
+ }
+ }
+
+ //synchronized void updateOps(KqueueSelectionKeyImpl key, int interestOps)
+ //{
+ // updateOps(key, interestOps, 0, false);
+ //}
+
+ /*void updateOps(KqueueSelectionKeyImpl key, int interestOps,
+ int activeOps, int fd)
+ {
+ //System.out.println(">> updating kqueue selection key:");
+ //dump_selection_keys(key.nstate.duplicate());
+ //System.out.println("<<");
+ synchronized (keys)
+ {
+ kevent_set(key.nstate, fd, interestOps, activeOps, key.key);
+ }
+ //System.out.println(">> updated kqueue selection key:");
+ //dump_selection_keys(key.nstate.duplicate());
+ //System.out.println("<<");
+ }*/
+
+ private void dump_selection_keys(ByteBuffer keys)
+ {
+ // WARNING! This method is not guaranteed to be portable! This works
+ // on darwin/x86, but the sizeof and offsetof these fields may be
+ // different on other platforms!
+ int i = 0;
+ keys.order(ByteOrder.nativeOrder());
+ while (keys.hasRemaining())
+ {
+ System.out.println("struct kevent { ident: "
+ + Integer.toString(keys.getInt())
+ + " filter: "
+ + Integer.toHexString(keys.getShort() & 0xFFFF)
+ + " flags: "
+ + Integer.toHexString(keys.getShort() & 0xFFFF)
+ + " fflags: "
+ + Integer.toHexString(keys.getInt())
+ + " data: "
+ + Integer.toHexString(keys.getInt())
+ + " udata: "
+ + Integer.toHexString(keys.getInt())
+ + " }");
+ }
+ }
+
+ /**
+ * Return the size of a <code>struct kevent</code> on this system.
+ *
+ * @return The size of <code>struct kevent</code>.
+ */
+ private static native int sizeof_struct_kevent();
+
+ /**
+ * Opens a kqueue descriptor.
+ *
+ * @return The new kqueue descriptor.
+ * @throws IOException If opening fails.
+ */
+ private static native int implOpen() throws IOException;
+
+ /**
+ * Closes the kqueue file descriptor.
+ *
+ * @param kq The kqueue file descriptor.
+ * @throws IOException
+ */
+ private static native void implClose(int kq) throws IOException;
+
+ /**
+ * Initialize the specified native state for the given interest ops.
+ *
+ * @param nstate The native state structures; in this buffer should be
+ * the <code>struct kevent</code>s created for a key.
+ * @param fd The file descriptor. If 0, the native FD is unmodified.
+ * @param interestOps The operations to enable.
+ * @param key A unique key that will reference the associated key later.
+ * @param delete Set to true if this event should be deleted from the
+ * kqueue (if false, this event is added/updated).
+ */
+ private static native void kevent_set(ByteBuffer nstate, int i, int fd,
+ int interestOps, int activeOps, int key);
+
+ /**
+ * Poll for events. The source events are stored in <code>events</code>,
+ * which is also where polled events will be placed.
+ *
+ * @param events The events to poll. This buffer is also the destination
+ * for events read from the queue.
+ * @param nevents The number of events to poll (that is, the number of
+ * events in the <code>events</code> buffer).
+ * @param nout The maximum number of events that may be returned.
+ * @param timeout The timeout. A timeout of -1 returns immediately; a timeout
+ * of 0 waits indefinitely.
+ * @return The number of events read.
+ */
+ private static native int kevent(int kq, ByteBuffer events, int nevents,
+ int nout, long timeout);
+
+ /**
+ * Fetch a polled key from a native state buffer. For each kevent key we
+ * create, we put the native state info (one or more <code>struct
+ * kevent</code>s) in that key's {@link KqueueSelectionKeyImpl#nstate}
+ * buffer, and place the pointer of the key in the <code>udata</code> field
+ * of that structure. This method fetches that pointer from the given
+ * buffer (assumed to be a <code>struct kqueue</code>) and returns it.
+ *
+ * @param nstate The buffer containing the <code>struct kqueue</code> to read.
+ * @return The key object.
+ */
+ private static native int fetch_key(ByteBuffer nstate);
+
+ /**
+ * Fetch the ready ops of the associated native state. That is, this
+ * inspects the first argument as a <code>struct kevent</code>, looking
+ * at its operation (the input is assumed to have been returned via a
+ * previous call to <code>kevent</code>), and translating that to the
+ * appropriate Java bit set, based on the second argument.
+ *
+ * @param nstate The native state.
+ * @param interestOps The enabled operations for the key.
+ * @return The bit set representing the ready operations.
+ */
+ private static native int ready_ops(ByteBuffer nstate, int interestOps);
+
+ /**
+ * Check if kevent returned EV_EOF for a selection key.
+ *
+ * @param nstate The native state.
+ * @return True if the kevent call returned EOF.
+ */
+ private static native boolean check_eof(ByteBuffer nstate);
+}
diff --git a/gnu/java/nio/NIOSocket.java b/gnu/java/nio/NIOSocket.java
index 4d812bf44..060a3a89c 100644
--- a/gnu/java/nio/NIOSocket.java
+++ b/gnu/java/nio/NIOSocket.java
@@ -48,30 +48,33 @@ import java.nio.channels.SocketChannel;
*/
public final class NIOSocket extends Socket
{
- private PlainSocketImpl impl;
private SocketChannelImpl channel;
- protected NIOSocket (PlainSocketImpl impl, SocketChannelImpl channel)
+ protected NIOSocket (SocketChannelImpl channel)
throws IOException
{
- super (impl);
- this.impl = impl;
+ super (new NIOSocketImpl(channel));
this.channel = channel;
}
- public final PlainSocketImpl getPlainSocketImpl()
- {
- return impl;
- }
+ //public final PlainSocketImpl getPlainSocketImpl()
+ //{
+ // return impl;
+ //}
- final void setChannel (SocketChannelImpl channel)
- {
- this.impl = channel.getPlainSocketImpl();
- this.channel = channel;
- }
+ //final void setChannel (SocketChannelImpl channel)
+ //{
+ // this.impl = channel.getPlainSocketImpl();
+ // this.channel = channel;
+ //}
public final SocketChannel getChannel()
{
return channel;
}
+
+ public boolean isConnected()
+ {
+ return channel.isConnected();
+ }
}
diff --git a/gnu/java/nio/NIOSocketImpl.java b/gnu/java/nio/NIOSocketImpl.java
new file mode 100644
index 000000000..4b26561a2
--- /dev/null
+++ b/gnu/java/nio/NIOSocketImpl.java
@@ -0,0 +1,110 @@
+/* NIOSocketImpl.java -- subclass of PlainSocketImpl for NIO.
+ 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 gnu.java.nio;
+
+import gnu.java.net.PlainSocketImpl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class NIOSocketImpl extends PlainSocketImpl
+{
+
+ private final SocketChannelImpl channel;
+
+ NIOSocketImpl(SocketChannelImpl channel) throws IOException
+ {
+ this.channel = channel;
+ impl.getState().setChannelFD(channel.getVMChannel().getState());
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getInetAddress()
+ */
+ //@Override
+ protected InetAddress getInetAddress()
+ {
+ try
+ {
+ return channel.getVMChannel().getPeerAddress().getAddress();
+ }
+ catch (IOException ioe)
+ {
+ return null;
+ }
+ catch (NullPointerException npe)
+ {
+ // Socket is not connected yet.
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.net.SocketImpl#getPort()
+ */
+ //@Override
+ protected int getPort()
+ {
+ try
+ {
+ return channel.getVMChannel().getPeerAddress().getPort();
+ }
+ catch (IOException ioe)
+ {
+ return -1;
+ }
+ catch (NullPointerException npe)
+ {
+ // Socket is not connected yet.
+ return -1;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.java.net.PlainSocketImpl#create(boolean)
+ */
+ //@Override
+ protected synchronized void create(boolean stream)
+ {
+ // Ignored; the socket has already been created.
+ }
+}
diff --git a/gnu/java/nio/PipeImpl.java b/gnu/java/nio/PipeImpl.java
index cccaa3988..8a95b9622 100644
--- a/gnu/java/nio/PipeImpl.java
+++ b/gnu/java/nio/PipeImpl.java
@@ -46,22 +46,21 @@ import java.nio.channels.spi.SelectorProvider;
class PipeImpl extends Pipe
{
public static final class SourceChannelImpl extends Pipe.SourceChannel
+ implements VMChannelOwner
{
- private int native_fd;
private VMChannel vmch;
public SourceChannelImpl (SelectorProvider selectorProvider,
- int native_fd)
+ VMChannel channel)
{
super (selectorProvider);
- this.native_fd = native_fd;
- vmch = VMChannel.getVMChannel(this);
+ vmch = channel;
}
protected final void implCloseSelectableChannel()
throws IOException
{
- throw new Error ("Not implemented");
+ vmch.close();
}
protected void implConfigureBlocking (boolean blocking)
@@ -94,30 +93,29 @@ class PipeImpl extends Pipe
return vmch.readScattering(srcs, offset, len);
}
-
- public final int getNativeFD()
+
+ public VMChannel getVMChannel()
{
- return native_fd;
+ return vmch;
}
}
public static final class SinkChannelImpl extends Pipe.SinkChannel
+ implements VMChannelOwner
{
- private int native_fd;
private VMChannel vmch;
public SinkChannelImpl (SelectorProvider selectorProvider,
- int native_fd)
+ VMChannel channel)
{
super (selectorProvider);
- this.native_fd = native_fd;
- vmch = VMChannel.getVMChannel(this);
+ vmch = channel;
}
protected final void implCloseSelectableChannel()
throws IOException
{
- throw new Error ("Not implemented");
+ vmch.close();
}
protected final void implConfigureBlocking (boolean blocking)
@@ -149,10 +147,10 @@ class PipeImpl extends Pipe
return vmch.writeGathering(srcs, offset, len);
}
-
- public final int getNativeFD()
+
+ public VMChannel getVMChannel()
{
- return native_fd;
+ return vmch;
}
}
@@ -163,7 +161,9 @@ class PipeImpl extends Pipe
throws IOException
{
super();
- VMPipe.init (this, provider);
+ VMChannel[] pipe = VMPipe.pipe();
+ sink = new SinkChannelImpl(provider, pipe[0]);
+ source = new SourceChannelImpl(provider, pipe[1]);
}
public Pipe.SinkChannel sink()
diff --git a/gnu/java/nio/SelectionKeyImpl.java b/gnu/java/nio/SelectionKeyImpl.java
index 8745377c5..c927f3196 100644
--- a/gnu/java/nio/SelectionKeyImpl.java
+++ b/gnu/java/nio/SelectionKeyImpl.java
@@ -106,5 +106,6 @@ public abstract class SelectionKeyImpl extends AbstractSelectionKey
return impl;
}
+ /* @deprecated */
public abstract int getNativeFD();
}
diff --git a/gnu/java/nio/SelectorProviderImpl.java b/gnu/java/nio/SelectorProviderImpl.java
index 47521107e..56167b69e 100644
--- a/gnu/java/nio/SelectorProviderImpl.java
+++ b/gnu/java/nio/SelectorProviderImpl.java
@@ -37,6 +37,9 @@ exception statement from your version. */
package gnu.java.nio;
+
+import gnu.classpath.SystemProperties;
+
import java.io.IOException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.Pipe;
@@ -47,6 +50,11 @@ import java.nio.channels.spi.SelectorProvider;
public class SelectorProviderImpl extends SelectorProvider
{
+ private static final String SELECTOR_IMPL_KQUEUE = "kqueue";
+ private static final String SELECTOR_IMPL_EPOLL = "epoll";
+ private static final String SELECTOR_IMPL = "gnu.java.nio.selectorImpl";
+ private static boolean epoll_failed = false;
+
public SelectorProviderImpl ()
{
}
@@ -66,6 +74,35 @@ public class SelectorProviderImpl extends SelectorProvider
public AbstractSelector openSelector ()
throws IOException
{
+ String selectorImpl = "default";
+ if (KqueueSelectorImpl.kqueue_supported())
+ selectorImpl = SELECTOR_IMPL_KQUEUE;
+ if (EpollSelectorImpl.epoll_supported() && !epoll_failed)
+ selectorImpl = SELECTOR_IMPL_EPOLL;
+ selectorImpl = SystemProperties.getProperty(SELECTOR_IMPL, selectorImpl);
+
+ if (selectorImpl.equals(SELECTOR_IMPL_KQUEUE))
+ return new KqueueSelectorImpl(this);
+
+ if (selectorImpl.equals(SELECTOR_IMPL_EPOLL))
+ {
+ // We jump through these hoops because even though epoll may look
+ // like it's available (sys/epoll.h exists, and you can link against
+ // all the epoll functions) it may not be available in the kernel
+ // (especially 2.4 kernels), meaning you will get ENOSYS at run time.
+ //
+ // Madness!
+ try
+ {
+ return new EpollSelectorImpl(this);
+ }
+ catch (InternalError e)
+ {
+ // epoll_create throws this on ENOSYS.
+ epoll_failed = true;
+ }
+ }
+
return new SelectorImpl (this);
}
diff --git a/gnu/java/nio/ServerSocketChannelImpl.java b/gnu/java/nio/ServerSocketChannelImpl.java
index c538ea802..1e8e0901d 100644
--- a/gnu/java/nio/ServerSocketChannelImpl.java
+++ b/gnu/java/nio/ServerSocketChannelImpl.java
@@ -48,7 +48,9 @@ import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
public final class ServerSocketChannelImpl extends ServerSocketChannel
+ implements VMChannelOwner
{
+ private VMChannel channel;
private NIOServerSocket serverSocket;
private boolean connected;
@@ -56,13 +58,15 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
throws IOException
{
super (provider);
- serverSocket = new NIOServerSocket (this);
+ serverSocket = new NIOServerSocket(this);
+ channel = serverSocket.getPlainSocketImpl().getVMChannel();
configureBlocking(true);
}
+ // XXX do we need this?
public void finalizer()
{
- if (connected)
+ if (channel.getState().isValid())
{
try
{
@@ -77,12 +81,12 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
protected void implCloseSelectableChannel () throws IOException
{
connected = false;
- serverSocket.close();
+ channel.close();
}
protected void implConfigureBlocking (boolean blocking) throws IOException
{
- serverSocket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ channel.setBlocking(blocking);
}
public SocketChannel accept () throws IOException
@@ -98,27 +102,28 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
try
{
begin();
- serverSocket.getPlainSocketImpl().setInChannelOperation(true);
- // indicate that a channel is initiating the accept operation
- // so that the socket ignores the fact that we might be in
- // non-blocking mode.
- NIOSocket socket = (NIOSocket) serverSocket.accept();
- completed = true;
- return socket.getChannel();
- }
- catch (SocketTimeoutException e)
- {
- return null;
+ VMChannel client = channel.accept();
+ if (client == null)
+ return null;
+ else
+ {
+ completed = true;
+ return new SocketChannelImpl(provider(), client, false);
+ }
}
finally
{
- serverSocket.getPlainSocketImpl().setInChannelOperation(false);
end (completed);
}
}
- public ServerSocket socket ()
+ public ServerSocket socket()
{
return serverSocket;
}
+
+ public VMChannel getVMChannel()
+ {
+ return channel;
+ }
}
diff --git a/gnu/java/nio/ServerSocketChannelSelectionKey.java b/gnu/java/nio/ServerSocketChannelSelectionKey.java
index d00c2b748..5b510cb6f 100644
--- a/gnu/java/nio/ServerSocketChannelSelectionKey.java
+++ b/gnu/java/nio/ServerSocketChannelSelectionKey.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
import java.nio.channels.spi.AbstractSelectableChannel;
public final class ServerSocketChannelSelectionKey
@@ -49,10 +50,16 @@ public final class ServerSocketChannelSelectionKey
super (channel, selector);
}
+ // FIXME don't use file descriptor integers
public int getNativeFD()
{
- NIOServerSocket socket =
- (NIOServerSocket) ((ServerSocketChannelImpl) ch).socket();
- return socket.getPlainSocketImpl().getNativeFD();
+ try
+ {
+ return ((ServerSocketChannelImpl) ch).getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalStateException(ioe);
+ }
}
}
diff --git a/gnu/java/nio/SocketChannelImpl.java b/gnu/java/nio/SocketChannelImpl.java
index 680eba2f9..1c563ac09 100644
--- a/gnu/java/nio/SocketChannelImpl.java
+++ b/gnu/java/nio/SocketChannelImpl.java
@@ -39,15 +39,20 @@ exception statement from your version. */
package gnu.java.nio;
import gnu.java.net.PlainSocketImpl;
+import gnu.java.net.VMPlainSocketImpl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
+import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ConnectionPendingException;
@@ -61,28 +66,57 @@ import java.nio.channels.UnsupportedAddressTypeException;
import java.nio.channels.spi.SelectorProvider;
public final class SocketChannelImpl extends SocketChannel
+ implements VMChannelOwner
{
- private PlainSocketImpl impl;
+ private VMChannel channel;
+ //private PlainSocketImpl impl;
private NIOSocket socket;
private boolean connectionPending;
+ private boolean connected;
+ private InetSocketAddress connectAddress;
+
+ public SocketChannelImpl(boolean create) throws IOException
+ {
+ // XXX consider adding security check; this is used by
+ // PlainSocketImpl.
+ this(new SelectorProviderImpl(), create);
+ }
+
+ public SocketChannelImpl(VMChannel channel) throws IOException
+ {
+ this(new SelectorProviderImpl(), channel, false);
+ }
+
+ SocketChannelImpl(SelectorProvider provider) throws IOException
+ {
+ this(provider, true);
+ }
- SocketChannelImpl (SelectorProvider provider)
+ SocketChannelImpl(SelectorProvider provider, boolean create)
+ throws IOException
+ {
+ this(provider, new VMChannel(), create);
+ }
+
+ SocketChannelImpl(SelectorProvider provider, VMChannel channel, boolean create)
throws IOException
{
super (provider);
- impl = new PlainSocketImpl();
- socket = new NIOSocket (impl, this);
+ this.channel = channel;
+ if (create)
+ channel.initSocket(true);
+ socket = new NIOSocket(this);
configureBlocking(true);
}
- SocketChannelImpl (SelectorProvider provider,
+ /*SocketChannelImpl (SelectorProvider provider,
NIOSocket socket)
throws IOException
{
super (provider);
this.impl = socket.getPlainSocketImpl();
this.socket = socket;
- }
+ }*/
public void finalizer()
{
@@ -98,23 +132,28 @@ public final class SocketChannelImpl extends SocketChannel
}
}
- PlainSocketImpl getPlainSocketImpl()
- {
- return impl;
- }
+ //PlainSocketImpl getPlainSocketImpl()
+ //{
+ // return null; // XXX
+ //}
- protected void implCloseSelectableChannel () throws IOException
+ protected void implCloseSelectableChannel() throws IOException
{
- socket.close();
+ channel.close();
}
protected void implConfigureBlocking (boolean blocking) throws IOException
{
- socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ channel.setBlocking(blocking);
}
public boolean connect (SocketAddress remote) throws IOException
{
+ return connect(remote, 0);
+ }
+
+ public boolean connect (SocketAddress remote, int timeout) throws IOException
+ {
if (!isOpen())
throw new ClosedChannelException();
@@ -126,79 +165,52 @@ public final class SocketChannelImpl extends SocketChannel
if (!(remote instanceof InetSocketAddress))
throw new UnsupportedAddressTypeException();
+
+ connectAddress = (InetSocketAddress) remote;
- if (((InetSocketAddress) remote).isUnresolved())
+ if (connectAddress.isUnresolved())
throw new UnresolvedAddressException();
- try
- {
- socket.getPlainSocketImpl().setInChannelOperation(true);
- // indicate that a channel is initiating the accept operation
- // so that the socket ignores the fact that we might be in
- // non-blocking mode.
-
- if (isBlocking())
- {
- // Do blocking connect.
- socket.connect (remote);
- return true;
- }
-
- // Do non-blocking connect.
- try
- {
- socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT);
- return true;
- }
- catch (SocketTimeoutException e)
- {
- connectionPending = true;
- return false;
- }
- }
- finally
- {
- socket.getPlainSocketImpl().setInChannelOperation(false);
- }
+ connected = channel.connect(connectAddress, timeout);
+ connectionPending = !connected;
+ return connected;
}
-
- public boolean finishConnect ()
+
+ public boolean finishConnect()
throws IOException
{
if (!isOpen())
throw new ClosedChannelException();
-
- if (!isConnected() && !connectionPending)
- throw new NoConnectionPendingException();
-
- if (isConnected())
- return true;
- // FIXME: Handle blocking/non-blocking mode.
-
- Selector selector = provider().openSelector();
- register(selector, SelectionKey.OP_CONNECT);
-
- if (isBlocking())
+ InetSocketAddress remote = channel.getPeerAddress();
+ if (remote != null)
{
- selector.select(); // blocking until channel is connected.
connectionPending = false;
return true;
}
-
- int ready = selector.selectNow(); // non-blocking
- if (ready == 1)
- {
- connectionPending = false;
- return true;
- }
-
+
+ if (!connectionPending)
+ throw new NoConnectionPendingException();
+
return false;
}
- public boolean isConnected ()
+ public boolean isConnected()
{
- return socket.isConnected();
+ // Wait until finishConnect is called before transitioning to
+ // connected.
+ if (connectionPending)
+ return false;
+ try
+ {
+ InetSocketAddress remote = channel.getPeerAddress();
+ return remote != null;
+ }
+ catch (IOException ioe)
+ {
+ ioe.printStackTrace(System.out);
+ return false;
+ }
}
public boolean isConnectionPending ()
@@ -216,52 +228,7 @@ public final class SocketChannelImpl extends SocketChannel
if (!isConnected())
throw new NotYetConnectedException();
- byte[] data;
- int offset = 0;
- InputStream input = socket.getInputStream();
- int available = input.available();
- int len = dst.remaining();
-
- if ((! isBlocking()) && available == 0)
- return 0;
-
- if (dst.hasArray())
- {
- offset = dst.arrayOffset() + dst.position();
- data = dst.array();
- }
- else
- {
- data = new byte [len];
- }
-
- int readBytes = 0;
- boolean completed = false;
-
- try
- {
- begin();
- socket.getPlainSocketImpl().setInChannelOperation(true);
- readBytes = input.read (data, offset, len);
- completed = true;
- }
- finally
- {
- end (completed);
- socket.getPlainSocketImpl().setInChannelOperation(false);
- }
-
- if (readBytes > 0)
- if (dst.hasArray())
- {
- dst.position (dst.position() + readBytes);
- }
- else
- {
- dst.put (data, offset, readBytes);
- }
-
- return readBytes;
+ return channel.read(dst);
}
public long read (ByteBuffer[] dsts, int offset, int length)
@@ -275,61 +242,19 @@ public final class SocketChannelImpl extends SocketChannel
|| (length < 0)
|| (length > (dsts.length - offset)))
throw new IndexOutOfBoundsException();
-
- long readBytes = 0;
-
- for (int index = offset; index < length; index++)
- readBytes += read (dsts [index]);
-
- return readBytes;
+
+ return channel.readScattering(dsts, offset, length);
}
- public int write (ByteBuffer src)
- throws IOException
+ public int write(ByteBuffer src) throws IOException
{
if (!isConnected())
throw new NotYetConnectedException();
-
- byte[] data;
- int offset = 0;
- int len = src.remaining();
-
- if (!src.hasArray())
- {
- data = new byte [len];
- src.get (data, 0, len);
- }
- else
- {
- offset = src.arrayOffset() + src.position();
- data = src.array();
- }
- OutputStream output = socket.getOutputStream();
- boolean completed = false;
-
- try
- {
- begin();
- socket.getPlainSocketImpl().setInChannelOperation(true);
- output.write (data, offset, len);
- completed = true;
- }
- finally
- {
- end (completed);
- socket.getPlainSocketImpl().setInChannelOperation(false);
- }
-
- if (src.hasArray())
- {
- src.position (src.position() + len);
- }
-
- return len;
+ return channel.write(src);
}
- public long write (ByteBuffer[] srcs, int offset, int length)
+ public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException
{
if (!isConnected())
@@ -340,12 +265,13 @@ public final class SocketChannelImpl extends SocketChannel
|| (length < 0)
|| (length > (srcs.length - offset)))
throw new IndexOutOfBoundsException();
-
- long writtenBytes = 0;
-
- for (int index = offset; index < length; index++)
- writtenBytes += write (srcs [index]);
- return writtenBytes;
+ return channel.writeGathering(srcs, offset, length);
+ }
+
+ public VMChannel getVMChannel()
+ {
+ // XXX security check?
+ return channel;
}
}
diff --git a/gnu/java/nio/SocketChannelSelectionKey.java b/gnu/java/nio/SocketChannelSelectionKey.java
index 75b4dfd87..9ceebdec9 100644
--- a/gnu/java/nio/SocketChannelSelectionKey.java
+++ b/gnu/java/nio/SocketChannelSelectionKey.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
import java.nio.channels.spi.AbstractSelectableChannel;
public final class SocketChannelSelectionKey
@@ -49,10 +50,16 @@ public final class SocketChannelSelectionKey
super (channel, selector);
}
+ // FIXME don't use file descriptor integers
public int getNativeFD()
{
- NIOSocket socket =
- (NIOSocket) ((SocketChannelImpl) ch).socket();
- return socket.getPlainSocketImpl().getNativeFD();
+ try
+ {
+ return ((SocketChannelImpl) ch).getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalStateException(ioe);
+ }
}
}
diff --git a/gnu/java/nio/SocketChannelSelectionKeyImpl.java b/gnu/java/nio/SocketChannelSelectionKeyImpl.java
index 30fb2dfba..31a96ed7d 100644
--- a/gnu/java/nio/SocketChannelSelectionKeyImpl.java
+++ b/gnu/java/nio/SocketChannelSelectionKeyImpl.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.java.nio;
+import java.io.IOException;
+
/**
* @author Michael Barker <mike@middlesoft.co.uk>
@@ -63,7 +65,14 @@ public class SocketChannelSelectionKeyImpl extends SelectionKeyImpl
*/
public int getNativeFD()
{
- return ch.getPlainSocketImpl().getNativeFD();
+ try
+ {
+ return ch.getVMChannel().getState().getNativeFD();
+ }
+ catch (IOException ioe)
+ {
+ return 0; // FIXME
+ }
}
}
diff --git a/gnu/java/nio/VMChannelOwner.java b/gnu/java/nio/VMChannelOwner.java
new file mode 100644
index 000000000..363dea2b2
--- /dev/null
+++ b/gnu/java/nio/VMChannelOwner.java
@@ -0,0 +1,57 @@
+/* NativeFD.java -- interface for Channels that have an underlying file descriptor.
+ 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 gnu.java.nio;
+
+/**
+ * This interface is meant to be implemented by any {@link Channel}
+ * implementation we support that uses a platform-specific {@link VMChannel}
+ * at their core. This is primarily used by {@link Selector} implementations,
+ * for easier access to the native state.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+interface VMChannelOwner
+{
+ /**
+ * Return the underlying platform-specific Channel instance.
+ *
+ * @return The platform channel object.
+ */
+ VMChannel getVMChannel();
+}
diff --git a/gnu/java/nio/charset/ByteCharset.java b/gnu/java/nio/charset/ByteCharset.java
index 2cc91b850..da0fdcbcd 100644
--- a/gnu/java/nio/charset/ByteCharset.java
+++ b/gnu/java/nio/charset/ByteCharset.java
@@ -156,6 +156,22 @@ abstract class ByteCharset extends Charset
}
}
+ public boolean canEncode(char c)
+ {
+ byte b = (c < lookup.length) ? lookup[c] : 0;
+ return b != 0 || c == 0;
+ }
+
+ public boolean canEncode(CharSequence cs)
+ {
+ for (int i = 0; i < cs.length(); ++i)
+ {
+ if (! canEncode(cs.charAt(i)))
+ return false;
+ }
+ return true;
+ }
+
protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out)
{
// TODO: Optimize this in the case in.hasArray() / out.hasArray()
diff --git a/gnu/java/nio/charset/ISO_8859_1.java b/gnu/java/nio/charset/ISO_8859_1.java
index cc06ecd5a..2a3073a32 100644
--- a/gnu/java/nio/charset/ISO_8859_1.java
+++ b/gnu/java/nio/charset/ISO_8859_1.java
@@ -128,6 +128,19 @@ final class ISO_8859_1 extends Charset
super (cs, 1.0f, 1.0f);
}
+ public boolean canEncode(char c)
+ {
+ return c <= 0xff;
+ }
+
+ public boolean canEncode(CharSequence cs)
+ {
+ for (int i = 0; i < cs.length(); ++i)
+ if (! canEncode(cs.charAt(i)))
+ return false;
+ return true;
+ }
+
protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out)
{
// TODO: Optimize this in the case in.hasArray() / out.hasArray()
diff --git a/gnu/java/nio/charset/US_ASCII.java b/gnu/java/nio/charset/US_ASCII.java
index d26f7ffc9..8888416be 100644
--- a/gnu/java/nio/charset/US_ASCII.java
+++ b/gnu/java/nio/charset/US_ASCII.java
@@ -134,6 +134,19 @@ final class US_ASCII extends Charset
super (cs, 1.0f, 1.0f);
}
+ public boolean canEncode(char c)
+ {
+ return c <= 0x7f;
+ }
+
+ public boolean canEncode(CharSequence cs)
+ {
+ for (int i = 0; i < cs.length(); ++i)
+ if (! canEncode(cs.charAt(i)))
+ return false;
+ return true;
+ }
+
protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out)
{
// TODO: Optimize this in the case in.hasArray() / out.hasArray()
@@ -141,7 +154,7 @@ final class US_ASCII extends Charset
{
char c = in.get ();
- if (c > Byte.MAX_VALUE)
+ if (c > 0x7f)
{
in.position (in.position () - 1);
return CoderResult.unmappableForLength (1);
diff --git a/gnu/java/rmi/server/ActivatableRef.java b/gnu/java/rmi/server/ActivatableRef.java
index d191c0c17..e7580bcd7 100644
--- a/gnu/java/rmi/server/ActivatableRef.java
+++ b/gnu/java/rmi/server/ActivatableRef.java
@@ -112,8 +112,10 @@ public class ActivatableRef extends UnicastRef
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException
{
- super.readExternal(in);
actId = (ActivationID) in.readObject();
+ String type = in.readUTF();
+ // XXX handle type.equals("") (null reference)
+ super.readExternal(in);
}
/**
@@ -121,8 +123,10 @@ public class ActivatableRef extends UnicastRef
*/
public void writeExternal(ObjectOutput out) throws IOException
{
- super.writeExternal(out);
out.writeObject(actId);
+ // XXX write a "" if the "nested" reference is a null reference
+ out.writeUTF("UnicastRef2");
+ super.writeExternal(out);
}
/**
diff --git a/gnu/java/util/prefs/GConfBasedPreferences.java b/gnu/java/util/prefs/GConfBasedPreferences.java
index 5702751cf..a7e2322b5 100644
--- a/gnu/java/util/prefs/GConfBasedPreferences.java
+++ b/gnu/java/util/prefs/GConfBasedPreferences.java
@@ -72,7 +72,6 @@ import java.util.prefs.BackingStoreException;
* <br />
*
* @author Mario Torre <neugens@limasoftware.net>
- * @version 1.0.1
*/
public class GConfBasedPreferences
extends AbstractPreferences
@@ -136,12 +135,20 @@ public class GConfBasedPreferences
absolutePath = absolutePath.substring(0, absolutePath.length() - 1);
}
+ // strip invalid characters
+ // please, note that all names are unescaped into the native peer
+ int index = absolutePath.lastIndexOf('/');
+ if (index > -1)
+ {
+ absolutePath = absolutePath.substring(0, index + 1);
+ absolutePath = absolutePath + GConfNativePeer.escapeString(name);
+ }
+
this.node = this.getRealRoot(isUser) + absolutePath;
boolean nodeExist = backend.nodeExist(this.node);
this.newNode = !nodeExist;
- backend.startWatchingNode(this.node);
}
/**
@@ -156,7 +163,15 @@ public class GConfBasedPreferences
// we don't check anything here, if the node is a new node this will be
// detected in the constructor, so we simply return a new reference to
// the requested node.
- return new GConfBasedPreferences(this, name, this.isUser);
+
+ GConfBasedPreferences preferenceNode
+ = new GConfBasedPreferences(this, name, this.isUser);
+
+ // register the node for to GConf so that it can listen
+ // events outside the scope of the application
+ backend.startWatchingNode(this.node);
+
+ return preferenceNode;
}
/**
@@ -365,6 +380,10 @@ public class GConfBasedPreferences
{
String nodeName = "";
+ // strip key
+ // please, note that all names are unescaped into the native peer
+ key = GConfNativePeer.escapeString(key);
+
if (this.node.endsWith("/"))
{
nodeName = this.node + key;
@@ -373,7 +392,7 @@ public class GConfBasedPreferences
{
nodeName = this.node + "/" + key;
}
-
+
return nodeName;
}
diff --git a/gnu/java/util/prefs/gconf/GConfNativePeer.java b/gnu/java/util/prefs/gconf/GConfNativePeer.java
index f1cb62787..6049863e9 100644
--- a/gnu/java/util/prefs/gconf/GConfNativePeer.java
+++ b/gnu/java/util/prefs/gconf/GConfNativePeer.java
@@ -45,7 +45,6 @@ import java.util.prefs.BackingStoreException;
* Native peer for GConf based preference backend.
*
* @author Mario Torre <neugens@limasoftware.net>
- * @version 1.0.1
*/
public final class GConfNativePeer
{
@@ -150,7 +149,7 @@ public final class GConfNativePeer
*/
public List getKeys(String node) throws BackingStoreException
{
- return gconf_client_gconf_client_all_keys(node);
+ return gconf_client_all_keys(node);
}
/**
@@ -162,10 +161,26 @@ public final class GConfNativePeer
*/
public List getChildrenNodes(String node) throws BackingStoreException
{
- return gconf_client_gconf_client_all_nodes(node);
+ return gconf_client_all_nodes(node);
}
/**
+ * Escape the given string so the it is a valid GConf name.
+ */
+ public static String escapeString(String plain)
+ {
+ return gconf_escape_key(plain);
+ }
+
+ /**
+ * Unescape a string escaped with {@link #escapeString}.
+ */
+ public static String unescapeString(String escaped)
+ {
+ return gconf_unescape_key(escaped);
+ }
+
+ /**
* Suggest to the backend GConf daemon to synch with the database.
*/
public void suggestSync() throws BackingStoreException
@@ -270,8 +285,9 @@ public final class GConfNativePeer
* Suggest to the GConf native peer a sync with the database.
*
*/
- native static final protected void gconf_client_suggest_sync();
-
+ native static final protected void gconf_client_suggest_sync()
+ throws BackingStoreException;
+
/**
* Returns a list of all nodes under the given node.
*
@@ -279,8 +295,9 @@ public final class GConfNativePeer
* @return A list of nodes under the given source node.
*/
native
- static final protected List gconf_client_gconf_client_all_nodes(String node);
-
+ static final protected List gconf_client_all_nodes(String node)
+ throws BackingStoreException;
+
/**
* Returns a list of all keys stored in the given node.
*
@@ -288,8 +305,28 @@ public final class GConfNativePeer
* @return A list of all keys stored in the given node.
*/
native
- static final protected List gconf_client_gconf_client_all_keys(String node);
+ static final protected List gconf_client_all_keys(String node)
+ throws BackingStoreException;
+ /**
+ * Escape the input String so that it's a valid element for GConf.
+ *
+ * @param plain the String to escape.
+ * @return An escaped String for use with GConf.
+ */
+ native
+ static final protected String gconf_escape_key(String plain);
+
+ /**
+ * Converts a string escaped with gconf_escape_key back into its
+ * original form.
+ *
+ * @param escaped key as returned by gconf_escape_key
+ * @return An unescaped key.
+ */
+ native
+ static final protected String gconf_unescape_key(String escaped);
+
static
{
System.loadLibrary("gconfpeer");
diff --git a/gnu/java/util/regex/RETokenRepeated.java b/gnu/java/util/regex/RETokenRepeated.java
index b32a316c4..7f5e5626f 100644
--- a/gnu/java/util/regex/RETokenRepeated.java
+++ b/gnu/java/util/regex/RETokenRepeated.java
@@ -38,8 +38,7 @@ exception statement from your version. */
package gnu.java.util.regex;
-// import java.util.Vector;
-// import java.util.Stack;
+import java.util.ArrayList;
final class RETokenRepeated extends REToken {
private REToken token;
@@ -168,19 +167,63 @@ final class RETokenRepeated extends REToken {
}
}
+ private static class FindMatchControlStack extends ArrayList {
+ private void push(FindMatchControl control) {
+ add(control);
+ }
+ private FindMatchControl pop() {
+ return (FindMatchControl)remove(size()-1);
+ }
+ private boolean empty() {
+ return isEmpty();
+ }
+ }
+
+ private static class FindMatchControl {
+ DoablesFinder finder;
+ FindMatchControl(DoablesFinder finder) {
+ this.finder = finder;
+ }
+ }
+
private REMatch findMatch(BacktrackStack stack) {
- // Avoid using recursive calls.
+ return findMatch(stack, new FindMatchControlStack());
+ }
+
+ private REMatch findMatch(BacktrackStack stack,
+ FindMatchControlStack controlStack) {
+ REMatch result = null;
+ StackedInfo si = null;
+ CharIndexed input = null;
+ int numRepeats = 0;
+ REMatch mymatch = null;
+ int[] visited = null;
+ DoablesFinder finder = null;
+
+ // Avoid using recursive calls because a match can be very long.
+
+ // This is the first entry point of this method.
+ // If you want to call this method recursively and you need the
+ // result returned, save necessary information in a FindMatchControl
+ // object and push it to controlStack, then continue from this point.
+ // You can check the result after exiting MAIN_LOOP.
+ MAIN_LOOP0:
+ while (true) {
+
+ // This is the second entry point of this method.
+ // If you want to call this method recursively but you do not need the
+ // result returned, just continue from this point.
MAIN_LOOP:
while (true) {
- if (stack.empty()) return null;
- StackedInfo si = (StackedInfo)(stack.peek());
- CharIndexed input = si.input;
- int numRepeats = si.numRepeats;
- REMatch mymatch = si.match;
- int[] visited = si.visited;
- DoablesFinder finder = si.finder;
-
+ if (stack.empty()) break MAIN_LOOP;
+ si = (StackedInfo)(stack.peek());
+ input = si.input;
+ numRepeats = si.numRepeats;
+ mymatch = si.match;
+ visited = si.visited;
+ finder = si.finder;
+
if (mymatch.backtrackStack == null)
mymatch.backtrackStack = new BacktrackStack();
@@ -192,12 +235,13 @@ final class RETokenRepeated extends REToken {
m1.backtrackStack.push(new BacktrackStack.Backtrack(
this, input, mymatch, stack));
}
- return m1;
+ result = m1;
+ break MAIN_LOOP;
}
if (stingy) {
continue MAIN_LOOP;
}
- return null;
+ break MAIN_LOOP;
}
if (finder == null) {
@@ -238,7 +282,8 @@ final class RETokenRepeated extends REToken {
m1.backtrackStack.push(new BacktrackStack.Backtrack(
this, input, mymatch, stack));
}
- return m1;
+ result = m1;
+ break MAIN_LOOP;
}
else {
continue MAIN_LOOP;
@@ -247,8 +292,82 @@ final class RETokenRepeated extends REToken {
visited = addVisited(mymatch.index, visited);
+ TryAnotherResult taresult = tryAnother(stack, input, mymatch, numRepeats, finder, visited);
+ visited = taresult.visited;
+ switch (taresult.status) {
+ case TryAnotherResult.TRY_FURTHER:
+ controlStack.push(new FindMatchControl(
+ finder));
+ continue MAIN_LOOP0;
+ case TryAnotherResult.RESULT_FOUND:
+ result = taresult.result;
+ break MAIN_LOOP;
+ }
+
+ if (!stack.empty()) {
+ stack.pop();
+ }
+ if (possessive) {
+ stack.clear();
+ }
+ REMatch m1 = matchRest(input, mymatch);
+ if (m1 != null) {
+ if (! stack.empty()) {
+ m1.backtrackStack.push(new BacktrackStack.Backtrack(
+ this, input, mymatch, stack));
+ }
+ result = m1;
+ break MAIN_LOOP;
+ }
+
+ } // MAIN_LOOP
+
+ if (controlStack.empty()) return result;
+ FindMatchControl control = controlStack.pop();
+ if (possessive) {
+ return result;
+ }
+ if (result != null) {
+ result.backtrackStack.push(new BacktrackStack.Backtrack(
+ this, input, mymatch, stack));
+ return result;
+ }
+
+ finder = control.finder;
+
+ TryAnotherResult taresult = tryAnother(stack, input, mymatch, numRepeats, finder, visited);
+ visited = taresult.visited;
+ switch (taresult.status) {
+ case TryAnotherResult.TRY_FURTHER:
+ controlStack.push(new FindMatchControl(
+ finder));
+ continue MAIN_LOOP0;
+ case TryAnotherResult.RESULT_FOUND:
+ return taresult.result;
+ }
+ continue MAIN_LOOP0;
+
+ } // MAIN_LOOP0
+ }
+
+ private static class TryAnotherResult {
+ REMatch result;
+ int status;
+ static final int RESULT_FOUND = 1;
+ static final int TRY_FURTHER = 2;
+ static final int NOTHING_FOUND = 3;
+ int[] visited;
+ }
+
+ private TryAnotherResult tryAnother(BacktrackStack stack,
+ CharIndexed input, REMatch mymatch, int numRepeats,
+ DoablesFinder finder, int[] visited) {
+
+ TryAnotherResult taresult = new TryAnotherResult();
+ taresult.visited = visited;
+
DO_THIS:
- do {
+ {
boolean emptyMatchFound = false;
@@ -263,58 +382,41 @@ final class RETokenRepeated extends REToken {
if (!emptyMatchFound) {
int n = doable.index;
- if (! visitedContains(n, visited)) {
- visited = addVisited(n, visited);
- }
- else {
+ if (visitedContains(n, visited)) {
continue DO_ONE_DOABLE;
}
+ visited = addVisited(n, visited);
stack.push(new StackedInfo(
- input, numRepeats + 1, doable, visited, null));
- REMatch m1 = findMatch(stack);
- if (possessive) {
- return m1;
- }
- if (m1 != null) {
- m1.backtrackStack.push(new BacktrackStack.Backtrack(
- this, input, mymatch, stack));
- return m1;
- }
+ input, numRepeats + 1, doable, visited, null));
+ taresult.visited = visited;
+ taresult.status = TryAnotherResult.TRY_FURTHER;
+ return taresult;
}
else {
REMatch m1 = matchRest(input, doable);
if (possessive) {
- return m1;
+ taresult.result = m1;
+ taresult.status = TryAnotherResult.RESULT_FOUND;
+ return taresult;
}
if (m1 != null) {
if (! stack.empty()) {
m1.backtrackStack.push(new BacktrackStack.Backtrack(
this, input, mymatch, stack));
- }
- return m1;
+ }
+ taresult.result = m1;
+ taresult.status = TryAnotherResult.RESULT_FOUND;
+ return taresult;
}
}
} // DO_ONE_DOABLE
- } while (false); // DO_THIS only once;
+ } // DO_THIS
- if (!stack.empty()) {
- stack.pop();
- }
- if (possessive) {
- stack.clear();
- }
- REMatch m1 = matchRest(input, mymatch);
- if (m1 != null) {
- if (! stack.empty()) {
- m1.backtrackStack.push(new BacktrackStack.Backtrack(
- this, input, mymatch, stack));
- }
- return m1;
- }
+ taresult.status = TryAnotherResult.NOTHING_FOUND;
+ return taresult;
- } // MAIN_LOOP
}
boolean match(CharIndexed input, REMatch mymatch) {